@expressive/mvc 1.0.0-beta.23 → 1.0.0-beta.27
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 +1235 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.js +218 -177
- package/lib/index.js.map +1 -0
- package/package.json +9 -15
- package/types/instructions.d.ts +61 -36
- package/types/model.d.ts +52 -21
- package/types/types.d.ts +3 -3
package/lib/index.js
CHANGED
|
@@ -96,14 +96,34 @@ class Subscriber {
|
|
|
96
96
|
constructor(parent, onUpdate) {
|
|
97
97
|
this.onUpdate = onUpdate;
|
|
98
98
|
this.active = false;
|
|
99
|
-
this.
|
|
99
|
+
this.handle = {};
|
|
100
100
|
this.dependant = new Set();
|
|
101
|
+
this.debug = () => {
|
|
102
|
+
const update = [];
|
|
103
|
+
this.notify = keys => {
|
|
104
|
+
update.splice(0, update.length, ...keys.filter(k => k in this.handle));
|
|
105
|
+
};
|
|
106
|
+
return update;
|
|
107
|
+
};
|
|
108
|
+
this.listen = (key, from) => {
|
|
109
|
+
const handler = this.handle[key];
|
|
110
|
+
if (!handler)
|
|
111
|
+
return;
|
|
112
|
+
if (typeof handler == "function")
|
|
113
|
+
handler();
|
|
114
|
+
const notify = this.onUpdate(key, from);
|
|
115
|
+
if (notify)
|
|
116
|
+
from.waiting.add(notify);
|
|
117
|
+
if (this.notify)
|
|
118
|
+
from.waiting.add(this.notify);
|
|
119
|
+
};
|
|
101
120
|
if (!(parent instanceof Controller))
|
|
102
121
|
parent = manage(parent);
|
|
103
122
|
this.parent = parent;
|
|
104
123
|
this.source = parent.subject;
|
|
105
124
|
this.proxy = create(parent.subject);
|
|
106
125
|
define(this.proxy, LOCAL, this);
|
|
126
|
+
defineLazy(this.proxy, UPDATE, this.debug);
|
|
107
127
|
for (const key in parent.state)
|
|
108
128
|
this.spy(key);
|
|
109
129
|
}
|
|
@@ -123,16 +143,15 @@ class Subscriber {
|
|
|
123
143
|
enumerable: true
|
|
124
144
|
});
|
|
125
145
|
}
|
|
126
|
-
follow(key,
|
|
127
|
-
this.
|
|
146
|
+
follow(key, callback) {
|
|
147
|
+
this.handle[key] = callback || true;
|
|
128
148
|
}
|
|
129
149
|
commit() {
|
|
130
|
-
const
|
|
131
|
-
const onDone = parent.addListener(follows);
|
|
150
|
+
const onDone = this.parent.addListener(this.listen);
|
|
132
151
|
this.active = true;
|
|
133
|
-
dependant.forEach(x => x.commit());
|
|
152
|
+
this.dependant.forEach(x => x.commit());
|
|
134
153
|
return this.release = () => {
|
|
135
|
-
dependant.forEach(x => x.release());
|
|
154
|
+
this.dependant.forEach(x => x.release());
|
|
136
155
|
onDone();
|
|
137
156
|
};
|
|
138
157
|
}
|
|
@@ -142,18 +161,23 @@ const Oops$8 = issues({
|
|
|
142
161
|
ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
143
162
|
ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
144
163
|
});
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
const
|
|
164
|
+
const INIT = new WeakSet();
|
|
165
|
+
const INFO = new WeakMap();
|
|
166
|
+
const USED = new WeakMap();
|
|
167
|
+
const KEYS = new WeakMap();
|
|
149
168
|
function prepare(parent, key, source, setter, getter) {
|
|
150
169
|
let sub;
|
|
151
170
|
const { state, subject } = parent;
|
|
152
171
|
const info = { key, parent, priority: 1 };
|
|
172
|
+
let register = USED.get(parent);
|
|
173
|
+
if (!register) {
|
|
174
|
+
register = new Map();
|
|
175
|
+
USED.set(parent, register);
|
|
176
|
+
}
|
|
177
|
+
register.set(key, info);
|
|
153
178
|
const current = getter
|
|
154
179
|
? () => getter.call(subject, state[key], key)
|
|
155
180
|
: () => state[key];
|
|
156
|
-
const prioritize = register(parent, key, info);
|
|
157
181
|
function compute(initial) {
|
|
158
182
|
try {
|
|
159
183
|
return setter.call(sub.proxy, sub.proxy);
|
|
@@ -178,8 +202,19 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
178
202
|
}
|
|
179
203
|
}
|
|
180
204
|
}
|
|
205
|
+
function defer(_key, from) {
|
|
206
|
+
let pending = KEYS.get(from);
|
|
207
|
+
if (!pending)
|
|
208
|
+
KEYS.set(from, pending = []);
|
|
209
|
+
if (info.parent !== from)
|
|
210
|
+
update();
|
|
211
|
+
else {
|
|
212
|
+
const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
|
|
213
|
+
pending.splice(after + 1, 0, update);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
181
216
|
function create(early) {
|
|
182
|
-
sub = new Subscriber(source(),
|
|
217
|
+
sub = new Subscriber(source(), defer);
|
|
183
218
|
defineProperty(state, key, {
|
|
184
219
|
value: undefined,
|
|
185
220
|
writable: true
|
|
@@ -199,16 +234,19 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
199
234
|
}
|
|
200
235
|
finally {
|
|
201
236
|
sub.commit();
|
|
202
|
-
for (const key in sub.
|
|
203
|
-
|
|
237
|
+
for (const key in sub.handle) {
|
|
238
|
+
const peer = register.get(key);
|
|
239
|
+
if (peer && peer.priority >= info.priority)
|
|
240
|
+
info.priority = peer.priority + 1;
|
|
241
|
+
}
|
|
204
242
|
}
|
|
205
243
|
return current();
|
|
206
244
|
}
|
|
207
245
|
setAlias(update, `try ${key}`);
|
|
208
246
|
setAlias(create, `new ${key}`);
|
|
209
247
|
setAlias(setter, `run ${key}`);
|
|
210
|
-
|
|
211
|
-
|
|
248
|
+
INIT.add(create);
|
|
249
|
+
INFO.set(update, info);
|
|
212
250
|
for (const on of [state, subject])
|
|
213
251
|
defineProperty(on, key, {
|
|
214
252
|
get: create,
|
|
@@ -216,53 +254,27 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
216
254
|
enumerable: true
|
|
217
255
|
});
|
|
218
256
|
}
|
|
219
|
-
function register(on, key, info) {
|
|
220
|
-
let register = ComputedUsed.get(on);
|
|
221
|
-
if (!register)
|
|
222
|
-
ComputedUsed.set(on, register = new Map());
|
|
223
|
-
register.set(key, info);
|
|
224
|
-
return (key) => {
|
|
225
|
-
const peer = register.get(key);
|
|
226
|
-
if (peer && peer.priority >= info.priority)
|
|
227
|
-
info.priority = peer.priority + 1;
|
|
228
|
-
};
|
|
229
|
-
}
|
|
230
257
|
function ensure(on, keys) {
|
|
231
258
|
for (const key of keys) {
|
|
232
259
|
const desc = getOwnPropertyDescriptor(on.subject, key);
|
|
233
260
|
const getter = desc && desc.get;
|
|
234
|
-
if (
|
|
261
|
+
if (INIT.has(getter))
|
|
235
262
|
getter(true);
|
|
236
263
|
}
|
|
237
264
|
}
|
|
238
|
-
function capture(on, request) {
|
|
239
|
-
const compute = ComputedInfo.get(request);
|
|
240
|
-
const callback = request;
|
|
241
|
-
if (!compute)
|
|
242
|
-
return;
|
|
243
|
-
let pending = ComputedKeys.get(on);
|
|
244
|
-
if (!pending)
|
|
245
|
-
ComputedKeys.set(on, pending = []);
|
|
246
|
-
if (compute.parent !== on)
|
|
247
|
-
callback();
|
|
248
|
-
else {
|
|
249
|
-
const queue = pending.findIndex(peer => compute.priority > ComputedInfo.get(peer).priority);
|
|
250
|
-
pending.splice(queue + 1, 0, callback);
|
|
251
|
-
}
|
|
252
|
-
return true;
|
|
253
|
-
}
|
|
254
265
|
function flush(on) {
|
|
255
266
|
const handled = on.frame;
|
|
256
|
-
|
|
257
|
-
if (pending)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
267
|
+
const pending = KEYS.get(on);
|
|
268
|
+
if (!pending)
|
|
269
|
+
return;
|
|
270
|
+
while (pending.length) {
|
|
271
|
+
const why = [...handled];
|
|
272
|
+
const compute = pending.shift();
|
|
273
|
+
const { key } = INFO.get(compute);
|
|
274
|
+
if (!handled.has(key))
|
|
275
|
+
compute(why);
|
|
276
|
+
}
|
|
277
|
+
KEYS.delete(on);
|
|
266
278
|
}
|
|
267
279
|
|
|
268
280
|
const Lifecycle = {
|
|
@@ -313,6 +325,7 @@ function eventsFor(prefix) {
|
|
|
313
325
|
}
|
|
314
326
|
|
|
315
327
|
const CONTROL = Symbol("control");
|
|
328
|
+
const UPDATE = Symbol("update");
|
|
316
329
|
const LOCAL = Symbol("local");
|
|
317
330
|
const STATE = Symbol("state");
|
|
318
331
|
function manage(src) {
|
|
@@ -341,8 +354,8 @@ class Controller {
|
|
|
341
354
|
this.subject = subject;
|
|
342
355
|
this.state = {};
|
|
343
356
|
this.frame = new Set();
|
|
344
|
-
this.
|
|
345
|
-
this.
|
|
357
|
+
this.waiting = new Set();
|
|
358
|
+
this.followers = new Set();
|
|
346
359
|
}
|
|
347
360
|
static setup(onto) {
|
|
348
361
|
const control = new this(onto);
|
|
@@ -408,18 +421,12 @@ class Controller {
|
|
|
408
421
|
this.update(key, value);
|
|
409
422
|
};
|
|
410
423
|
}
|
|
411
|
-
addListener(
|
|
412
|
-
this.
|
|
424
|
+
addListener(listener) {
|
|
425
|
+
this.followers.add(listener);
|
|
413
426
|
return () => {
|
|
414
|
-
this.
|
|
427
|
+
this.followers.delete(listener);
|
|
415
428
|
};
|
|
416
429
|
}
|
|
417
|
-
include(to) {
|
|
418
|
-
if (capture(this, to))
|
|
419
|
-
return;
|
|
420
|
-
else
|
|
421
|
-
this.waiting.push(to);
|
|
422
|
-
}
|
|
423
430
|
update(key, value) {
|
|
424
431
|
if (1 in arguments)
|
|
425
432
|
this.state[key] = value;
|
|
@@ -428,15 +435,22 @@ class Controller {
|
|
|
428
435
|
if (!this.frame.size)
|
|
429
436
|
setTimeout(() => this.emit(), 0);
|
|
430
437
|
this.frame.add(key);
|
|
431
|
-
for (const subscription of this.
|
|
432
|
-
|
|
433
|
-
|
|
438
|
+
for (const subscription of this.followers) {
|
|
439
|
+
const notify = subscription(key, this);
|
|
440
|
+
if (notify)
|
|
441
|
+
this.waiting.add(notify);
|
|
442
|
+
}
|
|
434
443
|
}
|
|
435
444
|
emit() {
|
|
436
445
|
flush(this);
|
|
437
|
-
const keys =
|
|
438
|
-
const handle = new Set(this.waiting
|
|
446
|
+
const keys = Object.freeze([...this.frame]);
|
|
447
|
+
const handle = new Set(this.waiting);
|
|
448
|
+
this.waiting.clear();
|
|
439
449
|
this.frame.clear();
|
|
450
|
+
defineProperty(this.subject, UPDATE, {
|
|
451
|
+
configurable: true,
|
|
452
|
+
value: keys
|
|
453
|
+
});
|
|
440
454
|
handle.forEach(callback => {
|
|
441
455
|
try {
|
|
442
456
|
callback(keys);
|
|
@@ -448,63 +462,66 @@ class Controller {
|
|
|
448
462
|
function keys(from, using) {
|
|
449
463
|
if (typeof using == "string")
|
|
450
464
|
return [using];
|
|
451
|
-
if (typeof using == "object")
|
|
452
|
-
|
|
465
|
+
if (typeof using == "object") {
|
|
466
|
+
using = Array.from(using);
|
|
467
|
+
if (using.length === 0)
|
|
468
|
+
using = undefined;
|
|
469
|
+
else
|
|
470
|
+
return using;
|
|
471
|
+
}
|
|
453
472
|
return from.select(using);
|
|
454
473
|
}
|
|
455
474
|
|
|
456
|
-
function child(
|
|
475
|
+
function child(source, name) {
|
|
457
476
|
return apply(function child(key) {
|
|
458
|
-
const
|
|
459
|
-
const
|
|
477
|
+
const context = new WeakMap();
|
|
478
|
+
const current = source.call(this, key);
|
|
460
479
|
function subscribe(sub) {
|
|
461
480
|
let child;
|
|
462
481
|
function start() {
|
|
463
|
-
const instance =
|
|
482
|
+
const instance = current();
|
|
464
483
|
if (instance) {
|
|
465
484
|
child = new Subscriber(instance, sub.onUpdate);
|
|
466
485
|
if (sub.active)
|
|
467
486
|
child.commit();
|
|
468
487
|
sub.dependant.add(child);
|
|
469
|
-
|
|
488
|
+
context.set(sub, child.proxy);
|
|
470
489
|
}
|
|
471
490
|
}
|
|
472
|
-
function
|
|
491
|
+
function restart() {
|
|
473
492
|
if (child) {
|
|
474
493
|
child.release();
|
|
475
494
|
sub.dependant.delete(child);
|
|
476
|
-
|
|
495
|
+
context.set(sub, undefined);
|
|
477
496
|
child = undefined;
|
|
478
497
|
}
|
|
479
498
|
start();
|
|
480
|
-
sub.onUpdate();
|
|
481
499
|
}
|
|
482
500
|
start();
|
|
483
|
-
sub.follow(key,
|
|
501
|
+
sub.follow(key, restart);
|
|
484
502
|
}
|
|
485
503
|
return (local) => {
|
|
486
504
|
if (!local)
|
|
487
|
-
return
|
|
488
|
-
if (!
|
|
505
|
+
return current();
|
|
506
|
+
if (!context.has(local))
|
|
489
507
|
subscribe(local);
|
|
490
|
-
return
|
|
508
|
+
return context.get(local);
|
|
491
509
|
};
|
|
492
|
-
}, name ||
|
|
510
|
+
}, name || source.name);
|
|
493
511
|
}
|
|
494
512
|
|
|
495
513
|
const Oops$7 = issues({
|
|
496
514
|
HasPropertyUndefined: (control, property) => `${control}.${property} is marked as required for this render.`
|
|
497
515
|
});
|
|
498
|
-
const useElementLifecycle = lifecycle("element");
|
|
499
516
|
function use$1(init) {
|
|
500
517
|
const [state, update] = react.useState(() => [
|
|
501
518
|
init(() => update(state.concat()))
|
|
502
519
|
]);
|
|
503
520
|
return state[0];
|
|
504
521
|
}
|
|
505
|
-
function useLazy(Type,
|
|
522
|
+
function useLazy(Type, callback) {
|
|
506
523
|
const instance = react.useMemo(() => {
|
|
507
|
-
const instance = Type.create(
|
|
524
|
+
const instance = Type.create();
|
|
508
525
|
if (callback)
|
|
509
526
|
callback(instance);
|
|
510
527
|
return instance;
|
|
@@ -514,7 +531,7 @@ function useLazy(Type, args, callback) {
|
|
|
514
531
|
}
|
|
515
532
|
function useWatcher(target, focus, expected) {
|
|
516
533
|
const hook = use$1(refresh => {
|
|
517
|
-
const sub = new Subscriber(target, refresh);
|
|
534
|
+
const sub = new Subscriber(target, () => refresh);
|
|
518
535
|
if (focus) {
|
|
519
536
|
const src = sub.proxy;
|
|
520
537
|
const key = keys(sub.parent, focus)[0];
|
|
@@ -531,21 +548,17 @@ function useWatcher(target, focus, expected) {
|
|
|
531
548
|
react.useLayoutEffect(() => hook.commit(), []);
|
|
532
549
|
return hook.proxy;
|
|
533
550
|
}
|
|
534
|
-
function
|
|
535
|
-
const hook = use$1(refresh => new Subscriber(target, refresh));
|
|
536
|
-
useElementLifecycle(hook, tag || 0);
|
|
537
|
-
return hook.proxy;
|
|
538
|
-
}
|
|
539
|
-
function useModel(Type, args, callback) {
|
|
551
|
+
function useModel(Type, callback) {
|
|
540
552
|
const hook = use$1(refresh => {
|
|
541
|
-
const instance = new Type(
|
|
553
|
+
const instance = new Type();
|
|
542
554
|
const control = manage(instance);
|
|
543
|
-
const sub = new Subscriber(control, refresh);
|
|
544
|
-
const release = control.addListener({
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
555
|
+
const sub = new Subscriber(control, () => refresh);
|
|
556
|
+
const release = control.addListener((key) => {
|
|
557
|
+
if (key == Lifecycle.WILL_UNMOUNT)
|
|
558
|
+
return () => {
|
|
559
|
+
instance.destroy();
|
|
560
|
+
release();
|
|
561
|
+
};
|
|
549
562
|
});
|
|
550
563
|
if (callback)
|
|
551
564
|
callback(instance);
|
|
@@ -711,7 +724,7 @@ function RenderFunction(props) {
|
|
|
711
724
|
const hook = use$1(refresh => {
|
|
712
725
|
const targets = props.context.local;
|
|
713
726
|
if (targets.length == 1)
|
|
714
|
-
return new Subscriber(targets[0], refresh);
|
|
727
|
+
return new Subscriber(targets[0], () => refresh);
|
|
715
728
|
return {};
|
|
716
729
|
});
|
|
717
730
|
if (hook.commit)
|
|
@@ -733,6 +746,7 @@ const Oops$4 = issues({
|
|
|
733
746
|
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
734
747
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
735
748
|
});
|
|
749
|
+
const useElementLifecycle = lifecycle("element");
|
|
736
750
|
const useComponentLifecycle = lifecycle("component");
|
|
737
751
|
class Model {
|
|
738
752
|
constructor() {
|
|
@@ -741,7 +755,7 @@ class Model {
|
|
|
741
755
|
define(this, "set", this);
|
|
742
756
|
defer(control, "on");
|
|
743
757
|
defer(control, "effect");
|
|
744
|
-
control.
|
|
758
|
+
control.waiting.add(() => {
|
|
745
759
|
delete this.on;
|
|
746
760
|
delete this.effect;
|
|
747
761
|
});
|
|
@@ -752,26 +766,37 @@ class Model {
|
|
|
752
766
|
return proxy;
|
|
753
767
|
}
|
|
754
768
|
tag(id) {
|
|
755
|
-
|
|
769
|
+
const hook = use$1(refresh => {
|
|
770
|
+
return new Subscriber(this, () => refresh);
|
|
771
|
+
});
|
|
772
|
+
useElementLifecycle(hook, id || 0);
|
|
773
|
+
return hook.proxy;
|
|
774
|
+
}
|
|
775
|
+
use(callback) {
|
|
776
|
+
const hook = use$1(refresh => {
|
|
777
|
+
if (callback)
|
|
778
|
+
callback(this);
|
|
779
|
+
return new Subscriber(this, () => refresh);
|
|
780
|
+
});
|
|
781
|
+
useComponentLifecycle(hook);
|
|
782
|
+
return hook.proxy;
|
|
756
783
|
}
|
|
757
784
|
on(subset, handler, squash, once) {
|
|
758
785
|
const control = manage(this);
|
|
759
|
-
const
|
|
760
|
-
const batch = {};
|
|
761
|
-
const remove = control.addListener(batch);
|
|
786
|
+
const request = keys(control, subset);
|
|
762
787
|
const callback = squash
|
|
763
788
|
? handler.bind(this)
|
|
764
|
-
:
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
}
|
|
769
|
-
const handle = once
|
|
770
|
-
? (k) => { remove(); callback(k); }
|
|
789
|
+
: frame => frame
|
|
790
|
+
.filter(k => request.includes(k))
|
|
791
|
+
.forEach(k => handler.call(this, control.state[k], k));
|
|
792
|
+
const trigger = once
|
|
793
|
+
? frame => { remove(); callback(frame); }
|
|
771
794
|
: callback;
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
795
|
+
ensure(control, request);
|
|
796
|
+
const remove = control.addListener(key => {
|
|
797
|
+
if (request.includes(key))
|
|
798
|
+
return trigger;
|
|
799
|
+
});
|
|
775
800
|
return remove;
|
|
776
801
|
}
|
|
777
802
|
once(select, callback, squash) {
|
|
@@ -792,7 +817,7 @@ class Model {
|
|
|
792
817
|
return this.on(select, invoke, true);
|
|
793
818
|
}
|
|
794
819
|
else {
|
|
795
|
-
const sub = new Subscriber(control, invoke);
|
|
820
|
+
const sub = new Subscriber(control, () => invoke);
|
|
796
821
|
target = sub.proxy;
|
|
797
822
|
invoke();
|
|
798
823
|
return sub.commit();
|
|
@@ -833,7 +858,7 @@ class Model {
|
|
|
833
858
|
then(callback) {
|
|
834
859
|
if (callback)
|
|
835
860
|
if (control.pending)
|
|
836
|
-
control.
|
|
861
|
+
control.waiting.add(callback);
|
|
837
862
|
else
|
|
838
863
|
callback(false);
|
|
839
864
|
else
|
|
@@ -852,8 +877,8 @@ class Model {
|
|
|
852
877
|
manage(instance);
|
|
853
878
|
return instance;
|
|
854
879
|
}
|
|
855
|
-
static new(
|
|
856
|
-
const instance = useLazy(this,
|
|
880
|
+
static new(callback) {
|
|
881
|
+
const instance = useLazy(this, callback);
|
|
857
882
|
instance.update("willRender", true);
|
|
858
883
|
return instance;
|
|
859
884
|
}
|
|
@@ -874,19 +899,19 @@ class Model {
|
|
|
874
899
|
static tag(id) {
|
|
875
900
|
return this.find(true).tag(id);
|
|
876
901
|
}
|
|
877
|
-
static use(
|
|
878
|
-
const instance = useModel(this,
|
|
902
|
+
static use(callback) {
|
|
903
|
+
const instance = useModel(this, callback);
|
|
879
904
|
useComponentLifecycle(instance[LOCAL]);
|
|
880
905
|
usePeerContext(instance.get);
|
|
881
906
|
return instance;
|
|
882
907
|
}
|
|
883
908
|
static uses(props, only) {
|
|
884
|
-
return this.use(
|
|
909
|
+
return this.use(instance => {
|
|
885
910
|
instance.import(props, only);
|
|
886
911
|
});
|
|
887
912
|
}
|
|
888
913
|
static using(props, only) {
|
|
889
|
-
const instance = this.use(
|
|
914
|
+
const instance = this.use();
|
|
890
915
|
instance.import(props, only);
|
|
891
916
|
return instance;
|
|
892
917
|
}
|
|
@@ -901,6 +926,7 @@ class Model {
|
|
|
901
926
|
Model.CONTROL = CONTROL;
|
|
902
927
|
Model.STATE = STATE;
|
|
903
928
|
Model.LOCAL = LOCAL;
|
|
929
|
+
Model.WHY = UPDATE;
|
|
904
930
|
defineLazy(Model, CONTROL, function () {
|
|
905
931
|
return new Controller(this).start();
|
|
906
932
|
});
|
|
@@ -909,7 +935,7 @@ function defer(on, method) {
|
|
|
909
935
|
const real = subject[method];
|
|
910
936
|
subject[method] = (...args) => {
|
|
911
937
|
let done;
|
|
912
|
-
waiting.
|
|
938
|
+
waiting.add(() => {
|
|
913
939
|
done = real.apply(subject, args);
|
|
914
940
|
});
|
|
915
941
|
return () => done();
|
|
@@ -921,7 +947,9 @@ const Oops$3 = issues({
|
|
|
921
947
|
ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
922
948
|
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
923
949
|
UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
|
|
924
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}
|
|
950
|
+
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
951
|
+
IsReadOnly: (owner, key) => `${owner}.${key} is set to read-only, but tried to reassign assign.`,
|
|
952
|
+
MustBeDefined: (owner, key) => `${owner}.${key} must have initial value, as a read-only property.`
|
|
925
953
|
});
|
|
926
954
|
function bootstrap(object) {
|
|
927
955
|
const breakdown = getOwnPropertyDescriptors(object);
|
|
@@ -932,34 +960,44 @@ function bootstrap(object) {
|
|
|
932
960
|
}
|
|
933
961
|
function use(input, argument) {
|
|
934
962
|
return child(function use(key) {
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
963
|
+
const { subject } = this;
|
|
964
|
+
// `true` => readonly
|
|
965
|
+
// `false` => writable, may be undefined
|
|
966
|
+
// `undefined` => writable (default)
|
|
967
|
+
let mode = argument;
|
|
968
|
+
let current;
|
|
969
|
+
const onUpdate = (next, initial) => {
|
|
970
|
+
if (mode === true && !initial)
|
|
971
|
+
throw Oops$3.IsReadOnly(subject, key);
|
|
972
|
+
if (next) {
|
|
973
|
+
current = next instanceof Model
|
|
974
|
+
? next : bootstrap(next);
|
|
975
|
+
Parent.set(current, subject);
|
|
976
|
+
manage(current);
|
|
943
977
|
}
|
|
944
|
-
if (
|
|
945
|
-
argument(instance);
|
|
946
|
-
else if (!instance && argument !== false)
|
|
978
|
+
else if (mode === undefined)
|
|
947
979
|
throw Oops$3.UndefinedNotAllowed(key);
|
|
980
|
+
else
|
|
981
|
+
current = undefined;
|
|
982
|
+
if (typeof argument == "function")
|
|
983
|
+
return argument(current);
|
|
948
984
|
};
|
|
949
985
|
if (input) {
|
|
950
|
-
|
|
986
|
+
current =
|
|
951
987
|
Model.isTypeof(input) ? new input() :
|
|
952
988
|
input instanceof Model ? input :
|
|
953
989
|
typeof input === "function" ? input() :
|
|
954
990
|
typeof input === "object" ? bootstrap(input) :
|
|
955
991
|
Oops$3.BadArgument(typeof input).throw();
|
|
956
|
-
if (
|
|
957
|
-
|
|
992
|
+
if (current)
|
|
993
|
+
mode = onUpdate(current, true) || mode;
|
|
994
|
+
else if (mode == true)
|
|
995
|
+
throw Oops$3.MustBeDefined(subject, key);
|
|
958
996
|
}
|
|
959
997
|
else
|
|
960
|
-
|
|
961
|
-
this.manage(key,
|
|
962
|
-
return () =>
|
|
998
|
+
mode = false;
|
|
999
|
+
this.manage(key, current, onUpdate);
|
|
1000
|
+
return () => current;
|
|
963
1001
|
});
|
|
964
1002
|
}
|
|
965
1003
|
function parent(Expects, required) {
|
|
@@ -977,6 +1015,31 @@ function parent(Expects, required) {
|
|
|
977
1015
|
});
|
|
978
1016
|
}
|
|
979
1017
|
|
|
1018
|
+
function on(initial, cb) {
|
|
1019
|
+
return apply(function on(key) {
|
|
1020
|
+
this.manage(key, initial, cb && createValueEffect(cb));
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
function memo(factory, defer) {
|
|
1024
|
+
return apply(function memo(key) {
|
|
1025
|
+
const source = this.subject;
|
|
1026
|
+
const get = () => factory.call(source);
|
|
1027
|
+
if (defer)
|
|
1028
|
+
defineLazy(source, key, get);
|
|
1029
|
+
else
|
|
1030
|
+
define(source, key, get());
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
function lazy(value) {
|
|
1034
|
+
return apply(function lazy(key) {
|
|
1035
|
+
const source = this.subject;
|
|
1036
|
+
source[key] = value;
|
|
1037
|
+
defineProperty(this.state, key, {
|
|
1038
|
+
get: () => source[key]
|
|
1039
|
+
});
|
|
1040
|
+
});
|
|
1041
|
+
}
|
|
1042
|
+
|
|
980
1043
|
const Oops$2 = issues({
|
|
981
1044
|
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
|
|
982
1045
|
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
@@ -1003,30 +1066,6 @@ function ref(arg) {
|
|
|
1003
1066
|
return { value };
|
|
1004
1067
|
});
|
|
1005
1068
|
}
|
|
1006
|
-
function on(initial, cb) {
|
|
1007
|
-
return apply(function on(key) {
|
|
1008
|
-
this.manage(key, initial, cb && createValueEffect(cb));
|
|
1009
|
-
});
|
|
1010
|
-
}
|
|
1011
|
-
function memo(factory, defer) {
|
|
1012
|
-
return apply(function memo(key) {
|
|
1013
|
-
const source = this.subject;
|
|
1014
|
-
const get = () => factory.call(source);
|
|
1015
|
-
if (defer)
|
|
1016
|
-
defineLazy(source, key, get);
|
|
1017
|
-
else
|
|
1018
|
-
define(source, key, get());
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
function lazy(value) {
|
|
1022
|
-
return apply(function lazy(key) {
|
|
1023
|
-
const source = this.subject;
|
|
1024
|
-
source[key] = value;
|
|
1025
|
-
defineProperty(this.state, key, {
|
|
1026
|
-
get: () => source[key]
|
|
1027
|
-
});
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
1069
|
function act(task) {
|
|
1031
1070
|
return apply(function act(key) {
|
|
1032
1071
|
let pending = false;
|
|
@@ -1099,13 +1138,14 @@ function pendingValue(via, key) {
|
|
|
1099
1138
|
return value;
|
|
1100
1139
|
const error = Oops$1.ValueNotReady(via.subject, key);
|
|
1101
1140
|
const promise = new Promise(resolve => {
|
|
1102
|
-
const release = via.addListener({
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1141
|
+
const release = via.addListener(forKey => {
|
|
1142
|
+
if (forKey == key)
|
|
1143
|
+
return () => {
|
|
1144
|
+
if (via.state[key] !== undefined) {
|
|
1145
|
+
release();
|
|
1146
|
+
resolve();
|
|
1147
|
+
}
|
|
1148
|
+
};
|
|
1109
1149
|
});
|
|
1110
1150
|
});
|
|
1111
1151
|
throw Object.assign(promise, {
|
|
@@ -1212,3 +1252,4 @@ exports.pending = pending;
|
|
|
1212
1252
|
exports.ref = ref;
|
|
1213
1253
|
exports.tap = tap;
|
|
1214
1254
|
exports.use = use;
|
|
1255
|
+
//# sourceMappingURL=index.js.map
|