@expressive/mvc 1.0.0-beta.32 → 1.0.0-beta.35
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 +851 -823
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +869 -836
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/types/context.d.ts +2 -2
- package/types/index.d.ts +1 -2
- package/types/instructions.d.ts +126 -53
- package/types/lifecycle.d.ts +13 -11
- package/types/model.d.ts +81 -147
- package/types/types.d.ts +1 -15
- package/types/selector.ts +0 -47
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
/*! *****************************************************************************
|
|
4
|
+
Copyright (c) Microsoft Corporation.
|
|
5
|
+
|
|
6
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
7
|
+
purpose with or without fee is hereby granted.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
***************************************************************************** */
|
|
17
|
+
|
|
18
|
+
function __rest(s, e) {
|
|
19
|
+
var t = {};
|
|
20
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
21
|
+
t[p] = s[p];
|
|
22
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
23
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
24
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
25
|
+
t[p[i]] = s[p[i]];
|
|
26
|
+
}
|
|
27
|
+
return t;
|
|
28
|
+
}
|
|
2
29
|
|
|
3
30
|
class Issue extends Error {
|
|
4
31
|
constructor() {
|
|
@@ -9,9 +36,6 @@ class Issue extends Error {
|
|
|
9
36
|
warn() {
|
|
10
37
|
console.warn(this.message);
|
|
11
38
|
}
|
|
12
|
-
throw() {
|
|
13
|
-
throw this;
|
|
14
|
-
}
|
|
15
39
|
}
|
|
16
40
|
function issues(register) {
|
|
17
41
|
const Library = {};
|
|
@@ -20,10 +44,10 @@ function issues(register) {
|
|
|
20
44
|
return Library;
|
|
21
45
|
}
|
|
22
46
|
|
|
23
|
-
const Oops$
|
|
47
|
+
const Oops$9 = issues({
|
|
24
48
|
BadEffectCallback: () => `Callback for effect-callback may only return a function.`
|
|
25
49
|
});
|
|
26
|
-
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertyDescriptors, getOwnPropertySymbols, keys
|
|
50
|
+
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertyDescriptors, getOwnPropertySymbols, keys, values } = Object;
|
|
27
51
|
function define(target, key, value) {
|
|
28
52
|
defineProperty(target, key, { value });
|
|
29
53
|
}
|
|
@@ -49,7 +73,7 @@ function createEffect(callback) {
|
|
|
49
73
|
if (unSet instanceof Promise)
|
|
50
74
|
unSet = undefined;
|
|
51
75
|
if (unSet && typeof unSet !== "function")
|
|
52
|
-
throw Oops$
|
|
76
|
+
throw Oops$9.BadEffectCallback();
|
|
53
77
|
};
|
|
54
78
|
}
|
|
55
79
|
function createValueEffect(callback) {
|
|
@@ -57,7 +81,7 @@ function createValueEffect(callback) {
|
|
|
57
81
|
return function (value) {
|
|
58
82
|
if (typeof unSet == "function")
|
|
59
83
|
unSet(value);
|
|
60
|
-
const out = callback.call(this, value);
|
|
84
|
+
const out = callback.call(this, value, this);
|
|
61
85
|
if (typeof out == "boolean")
|
|
62
86
|
return out;
|
|
63
87
|
if (!out || out instanceof Promise)
|
|
@@ -65,95 +89,182 @@ function createValueEffect(callback) {
|
|
|
65
89
|
if (typeof out == "function")
|
|
66
90
|
unSet = out;
|
|
67
91
|
else
|
|
68
|
-
throw Oops$
|
|
92
|
+
throw Oops$9.BadEffectCallback();
|
|
69
93
|
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const Oops$8 = issues({
|
|
97
|
+
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
98
|
+
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
99
|
+
});
|
|
100
|
+
class Controller {
|
|
101
|
+
constructor(subject) {
|
|
102
|
+
this.subject = subject;
|
|
103
|
+
this.frame = new Set();
|
|
104
|
+
this.waiting = new Set();
|
|
105
|
+
this.followers = new Set();
|
|
106
|
+
}
|
|
107
|
+
start() {
|
|
108
|
+
this.state = {};
|
|
109
|
+
for (const key in this.subject)
|
|
110
|
+
this.manage(key);
|
|
111
|
+
const handle = new Set(this.waiting);
|
|
112
|
+
this.waiting.clear();
|
|
113
|
+
handle.forEach(cb => cb([]));
|
|
114
|
+
return this;
|
|
115
|
+
}
|
|
116
|
+
manage(key, handler) {
|
|
117
|
+
const { state, subject } = this;
|
|
118
|
+
const desc = getOwnPropertyDescriptor(subject, key);
|
|
119
|
+
if (desc && "value" in desc) {
|
|
120
|
+
const { value } = desc;
|
|
121
|
+
const instruction = Pending.get(value);
|
|
122
|
+
if (instruction) {
|
|
123
|
+
Pending.delete(value);
|
|
124
|
+
delete subject[key];
|
|
125
|
+
instruction.call(this, key, this);
|
|
85
126
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
127
|
+
else if (typeof value !== "function" || /^[A-Z]/.test(key)) {
|
|
128
|
+
state[key] = value;
|
|
129
|
+
defineProperty(subject, key, {
|
|
130
|
+
enumerable: true,
|
|
131
|
+
get: () => state[key],
|
|
132
|
+
set: this.setter(key, handler)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
setter(key, handler) {
|
|
138
|
+
const { state, subject } = this;
|
|
139
|
+
return (value) => {
|
|
140
|
+
if (state[key] == value)
|
|
141
|
+
return;
|
|
142
|
+
if (handler)
|
|
143
|
+
switch (handler.call(subject, value, state)) {
|
|
144
|
+
case true:
|
|
145
|
+
this.update(key);
|
|
146
|
+
case false:
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.update(key, value);
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
addListener(listener) {
|
|
153
|
+
this.followers.add(listener);
|
|
154
|
+
return () => {
|
|
155
|
+
this.followers.delete(listener);
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
update(key, value) {
|
|
159
|
+
if (1 in arguments)
|
|
160
|
+
this.state[key] = value;
|
|
161
|
+
if (this.frame.has(key))
|
|
162
|
+
return;
|
|
163
|
+
if (!this.frame.size)
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
flush(this);
|
|
166
|
+
const keys = Object.freeze([...this.frame]);
|
|
167
|
+
const handle = new Set(this.waiting);
|
|
168
|
+
this.waiting.clear();
|
|
169
|
+
this.frame.clear();
|
|
170
|
+
UPDATE.set(this.subject, keys);
|
|
171
|
+
setImmediate(() => {
|
|
172
|
+
UPDATE.delete(this.subject);
|
|
173
|
+
});
|
|
174
|
+
handle.forEach(callback => {
|
|
175
|
+
try {
|
|
176
|
+
callback(keys);
|
|
177
|
+
}
|
|
178
|
+
catch (e) { }
|
|
179
|
+
});
|
|
180
|
+
}, 0);
|
|
181
|
+
this.frame.add(key);
|
|
182
|
+
for (const callback of this.followers) {
|
|
183
|
+
const event = callback(key, this);
|
|
184
|
+
if (typeof event == "function")
|
|
185
|
+
this.waiting.add(event);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
requestUpdate(arg) {
|
|
189
|
+
if (typeof arg == "function") {
|
|
190
|
+
this.waiting.add(arg);
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (typeof arg == "boolean" && arg !== this.frame.size > 0)
|
|
194
|
+
return Promise.reject(Oops$8.StrictUpdate(arg));
|
|
195
|
+
return {
|
|
196
|
+
then: (callback) => {
|
|
197
|
+
if (callback)
|
|
198
|
+
if (this.frame.size)
|
|
199
|
+
this.waiting.add(callback);
|
|
200
|
+
else
|
|
201
|
+
callback(false);
|
|
202
|
+
else
|
|
203
|
+
throw Oops$8.NoChaining();
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
89
207
|
}
|
|
90
208
|
|
|
91
209
|
class Subscriber {
|
|
92
210
|
constructor(parent, onUpdate) {
|
|
93
211
|
this.onUpdate = onUpdate;
|
|
94
212
|
this.active = false;
|
|
95
|
-
this.
|
|
213
|
+
this.watch = {};
|
|
96
214
|
this.dependant = new Set();
|
|
97
|
-
this.listen = (key, from) => {
|
|
98
|
-
const handler = this.handle[key];
|
|
99
|
-
if (!handler)
|
|
100
|
-
return;
|
|
101
|
-
if (typeof handler == "function")
|
|
102
|
-
handler();
|
|
103
|
-
const notify = this.onUpdate(key, from);
|
|
104
|
-
if (notify)
|
|
105
|
-
from.waiting.add(notify);
|
|
106
|
-
};
|
|
107
215
|
if (!(parent instanceof Controller))
|
|
108
|
-
parent =
|
|
109
|
-
const subject = this.source =
|
|
110
|
-
parent.subject;
|
|
111
|
-
const proxy = this.proxy =
|
|
112
|
-
create(subject);
|
|
216
|
+
parent = getController(parent);
|
|
113
217
|
this.parent = parent;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
218
|
+
this.source = parent.subject;
|
|
219
|
+
const proxy = this.proxy = create(parent.subject);
|
|
220
|
+
const DEBUG = (keys) => {
|
|
221
|
+
UPDATE.set(proxy, keys.filter(k => k in this.watch));
|
|
222
|
+
};
|
|
223
|
+
define(proxy, LOCAL, this);
|
|
224
|
+
defineProperty(this, "proxy", {
|
|
225
|
+
get: () => {
|
|
226
|
+
if (UPDATE.has(proxy))
|
|
227
|
+
setImmediate(() => {
|
|
228
|
+
UPDATE.delete(proxy);
|
|
229
|
+
});
|
|
230
|
+
return proxy;
|
|
231
|
+
}
|
|
117
232
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
233
|
+
for (const key in parent.state) {
|
|
234
|
+
const existing = getOwnPropertyDescriptor(parent.subject, key);
|
|
235
|
+
const isUsing = () => {
|
|
236
|
+
this.watch[key] = true;
|
|
237
|
+
delete proxy[key];
|
|
238
|
+
return proxy[key];
|
|
239
|
+
};
|
|
240
|
+
setAlias(isUsing, `tap ${key}`);
|
|
241
|
+
defineProperty(proxy, key, {
|
|
242
|
+
set: existing.set,
|
|
243
|
+
get: isUsing,
|
|
244
|
+
configurable: true,
|
|
245
|
+
enumerable: true
|
|
126
246
|
});
|
|
127
247
|
}
|
|
128
|
-
|
|
129
|
-
this
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
this.handle[key] = callback || true;
|
|
149
|
-
}
|
|
150
|
-
commit() {
|
|
151
|
-
const onDone = this.parent.addListener(this.listen);
|
|
152
|
-
this.active = true;
|
|
153
|
-
this.dependant.forEach(x => x.commit());
|
|
154
|
-
return this.release = () => {
|
|
155
|
-
this.dependant.forEach(x => x.release());
|
|
156
|
-
onDone();
|
|
248
|
+
this.commit = () => {
|
|
249
|
+
const { parent } = this;
|
|
250
|
+
const onDone = parent.addListener(key => {
|
|
251
|
+
const handler = this.watch[key];
|
|
252
|
+
if (!handler)
|
|
253
|
+
return;
|
|
254
|
+
if (typeof handler == "function")
|
|
255
|
+
handler();
|
|
256
|
+
const notify = this.onUpdate(key, parent);
|
|
257
|
+
if (notify) {
|
|
258
|
+
parent.requestUpdate(DEBUG);
|
|
259
|
+
parent.requestUpdate(notify);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
this.active = true;
|
|
263
|
+
this.dependant.forEach(x => x.commit());
|
|
264
|
+
return this.release = () => {
|
|
265
|
+
this.dependant.forEach(x => x.release());
|
|
266
|
+
onDone();
|
|
267
|
+
};
|
|
157
268
|
};
|
|
158
269
|
}
|
|
159
270
|
}
|
|
@@ -177,7 +288,7 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
177
288
|
}
|
|
178
289
|
register.set(key, info);
|
|
179
290
|
const current = getter
|
|
180
|
-
? () => getter
|
|
291
|
+
? () => getter(parent, key)
|
|
181
292
|
: () => state[key];
|
|
182
293
|
function compute(initial) {
|
|
183
294
|
try {
|
|
@@ -235,7 +346,7 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
235
346
|
}
|
|
236
347
|
finally {
|
|
237
348
|
sub.commit();
|
|
238
|
-
for (const key in sub.
|
|
349
|
+
for (const key in sub.watch) {
|
|
239
350
|
const peer = register.get(key);
|
|
240
351
|
if (peer && peer.priority >= info.priority)
|
|
241
352
|
info.priority = peer.priority + 1;
|
|
@@ -255,7 +366,7 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
255
366
|
enumerable: true
|
|
256
367
|
});
|
|
257
368
|
}
|
|
258
|
-
function ensure(on, keys) {
|
|
369
|
+
function ensure$1(on, keys) {
|
|
259
370
|
for (const key of keys) {
|
|
260
371
|
const desc = getOwnPropertyDescriptor(on.subject, key);
|
|
261
372
|
const getter = desc && desc.get;
|
|
@@ -278,6 +389,287 @@ function flush(on) {
|
|
|
278
389
|
KEYS.delete(on);
|
|
279
390
|
}
|
|
280
391
|
|
|
392
|
+
const CONTROL = Symbol("CONTROL");
|
|
393
|
+
const WHY = Symbol("UPDATE");
|
|
394
|
+
const LOCAL = Symbol("LOCAL");
|
|
395
|
+
const STATE = Symbol("STATE");
|
|
396
|
+
const UPDATE = new WeakMap();
|
|
397
|
+
function ensure(subject, callback) {
|
|
398
|
+
const control = subject[CONTROL];
|
|
399
|
+
if (!control.state) {
|
|
400
|
+
let done;
|
|
401
|
+
control.requestUpdate(() => {
|
|
402
|
+
done = callback(control);
|
|
403
|
+
});
|
|
404
|
+
return () => done();
|
|
405
|
+
}
|
|
406
|
+
return callback(control);
|
|
407
|
+
}
|
|
408
|
+
function getController(subject) {
|
|
409
|
+
const control = subject[CONTROL];
|
|
410
|
+
if (!control.state)
|
|
411
|
+
control.start();
|
|
412
|
+
if (subject.didCreate)
|
|
413
|
+
subject.didCreate();
|
|
414
|
+
return control;
|
|
415
|
+
}
|
|
416
|
+
class Model {
|
|
417
|
+
constructor() {
|
|
418
|
+
define(this, CONTROL, new Controller(this));
|
|
419
|
+
define(this, "get", this);
|
|
420
|
+
define(this, "set", this);
|
|
421
|
+
}
|
|
422
|
+
get [STATE]() {
|
|
423
|
+
return this[CONTROL].state;
|
|
424
|
+
}
|
|
425
|
+
get [WHY]() {
|
|
426
|
+
return UPDATE.get(this);
|
|
427
|
+
}
|
|
428
|
+
on(select, handler, squash, once) {
|
|
429
|
+
return ensure(this, control => {
|
|
430
|
+
const keys = typeof select == "string" ? [select] :
|
|
431
|
+
!select.length ? getOwnPropertyNames(control.state) :
|
|
432
|
+
select;
|
|
433
|
+
ensure$1(control, keys);
|
|
434
|
+
const callback = squash
|
|
435
|
+
? handler.bind(this)
|
|
436
|
+
: frame => frame
|
|
437
|
+
.filter(k => keys.includes(k))
|
|
438
|
+
.forEach(k => handler.call(this, control.state[k], k));
|
|
439
|
+
const trigger = once
|
|
440
|
+
? frame => { remove(); callback(frame); }
|
|
441
|
+
: callback;
|
|
442
|
+
const remove = control.addListener(key => {
|
|
443
|
+
if (keys.includes(key))
|
|
444
|
+
return trigger;
|
|
445
|
+
});
|
|
446
|
+
return remove;
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
once(select, callback, squash) {
|
|
450
|
+
if (callback)
|
|
451
|
+
return this.on(select, callback, squash, true);
|
|
452
|
+
return new Promise(resolve => {
|
|
453
|
+
this.on(select, resolve, true, true);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
effect(callback, select) {
|
|
457
|
+
const effect = createEffect(callback);
|
|
458
|
+
return ensure(this, control => {
|
|
459
|
+
if (!select) {
|
|
460
|
+
const sub = new Subscriber(control, () => invoke);
|
|
461
|
+
const invoke = () => {
|
|
462
|
+
const x = sub.proxy;
|
|
463
|
+
effect.call(x, x);
|
|
464
|
+
};
|
|
465
|
+
invoke();
|
|
466
|
+
return sub.commit();
|
|
467
|
+
}
|
|
468
|
+
const invoke = () => {
|
|
469
|
+
effect.call(this.get, this.get);
|
|
470
|
+
};
|
|
471
|
+
invoke();
|
|
472
|
+
if (!select.length)
|
|
473
|
+
select.push("willDestroy");
|
|
474
|
+
return control.addListener(key => {
|
|
475
|
+
if (select.includes(key))
|
|
476
|
+
return invoke;
|
|
477
|
+
});
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
import(from, subset) {
|
|
481
|
+
for (const key of subset || getOwnPropertyNames(this))
|
|
482
|
+
if (key in from)
|
|
483
|
+
this[key] = from[key];
|
|
484
|
+
}
|
|
485
|
+
export(subset) {
|
|
486
|
+
const { state } = getController(this);
|
|
487
|
+
const output = {};
|
|
488
|
+
for (const key of subset || getOwnPropertyNames(state))
|
|
489
|
+
output[key] = state[key];
|
|
490
|
+
return output;
|
|
491
|
+
}
|
|
492
|
+
update(arg, tag) {
|
|
493
|
+
const control = getController(this);
|
|
494
|
+
if (typeof arg == "string") {
|
|
495
|
+
control.update(arg);
|
|
496
|
+
if (1 in arguments && arg in this) {
|
|
497
|
+
const method = this[arg];
|
|
498
|
+
if (typeof method == "function")
|
|
499
|
+
if (typeof tag != "boolean")
|
|
500
|
+
method.call(this, tag);
|
|
501
|
+
else if (tag)
|
|
502
|
+
method.call(this);
|
|
503
|
+
}
|
|
504
|
+
arg = undefined;
|
|
505
|
+
}
|
|
506
|
+
return control.requestUpdate(arg);
|
|
507
|
+
}
|
|
508
|
+
destroy() {
|
|
509
|
+
this.update("willDestroy", true);
|
|
510
|
+
}
|
|
511
|
+
toString() {
|
|
512
|
+
return this.constructor.name;
|
|
513
|
+
}
|
|
514
|
+
static create(...args) {
|
|
515
|
+
const instance = new this(...args);
|
|
516
|
+
getController(instance);
|
|
517
|
+
return instance;
|
|
518
|
+
}
|
|
519
|
+
static isTypeof(maybe) {
|
|
520
|
+
return (typeof maybe == "function" &&
|
|
521
|
+
maybe.prototype instanceof this);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
Model.CONTROL = CONTROL;
|
|
525
|
+
Model.STATE = STATE;
|
|
526
|
+
Model.LOCAL = LOCAL;
|
|
527
|
+
Model.WHY = WHY;
|
|
528
|
+
defineLazy(Model, CONTROL, function () {
|
|
529
|
+
return new Controller(this);
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
const Pending = new Map();
|
|
533
|
+
function apply(fn, label) {
|
|
534
|
+
const name = label || fn.name || "pending";
|
|
535
|
+
const placeholder = Symbol(`${name} instruction`);
|
|
536
|
+
function setup(key) {
|
|
537
|
+
const { subject, state } = this;
|
|
538
|
+
let output = fn.call(this, key, this);
|
|
539
|
+
let desc = {};
|
|
540
|
+
let get;
|
|
541
|
+
let set;
|
|
542
|
+
if (!output)
|
|
543
|
+
return;
|
|
544
|
+
if (typeof output == "function")
|
|
545
|
+
get = output;
|
|
546
|
+
else {
|
|
547
|
+
(({ get, set } = output), desc = __rest(output, ["get", "set"]));
|
|
548
|
+
if ("value" in desc) {
|
|
549
|
+
state[key] = desc.value;
|
|
550
|
+
if (get || set)
|
|
551
|
+
delete desc.value;
|
|
552
|
+
else {
|
|
553
|
+
defineProperty(subject, key, desc);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
defineProperty(subject, key, Object.assign(Object.assign({}, desc), { set: this.setter(key, set), get: get
|
|
559
|
+
? function () {
|
|
560
|
+
return get(state[key], this[LOCAL]);
|
|
561
|
+
}
|
|
562
|
+
: () => state[key] }));
|
|
563
|
+
}
|
|
564
|
+
Pending.set(placeholder, setup);
|
|
565
|
+
return placeholder;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
//TODO: sync instruction
|
|
569
|
+
function child(source, name) {
|
|
570
|
+
return apply(function child(key) {
|
|
571
|
+
const context = new WeakMap();
|
|
572
|
+
const peer = source.call(this, key);
|
|
573
|
+
function subscribe(sub) {
|
|
574
|
+
let child;
|
|
575
|
+
function init() {
|
|
576
|
+
if (child) {
|
|
577
|
+
child.release();
|
|
578
|
+
sub.dependant.delete(child);
|
|
579
|
+
context.set(sub, undefined);
|
|
580
|
+
child = undefined;
|
|
581
|
+
}
|
|
582
|
+
const instance = peer.get();
|
|
583
|
+
if (instance) {
|
|
584
|
+
child = new Subscriber(instance, sub.onUpdate);
|
|
585
|
+
if (sub.active)
|
|
586
|
+
child.commit();
|
|
587
|
+
sub.dependant.add(child);
|
|
588
|
+
context.set(sub, child.proxy);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
init();
|
|
592
|
+
sub.watch[key] = init;
|
|
593
|
+
}
|
|
594
|
+
return {
|
|
595
|
+
value: peer.get(),
|
|
596
|
+
set: peer.set,
|
|
597
|
+
get(_value, local) {
|
|
598
|
+
if (!local)
|
|
599
|
+
return peer.get();
|
|
600
|
+
if (!context.has(local))
|
|
601
|
+
subscribe(local);
|
|
602
|
+
return context.get(local);
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
}, name || source.name);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const Parent = new WeakMap();
|
|
609
|
+
const Oops$6 = issues({
|
|
610
|
+
ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
611
|
+
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
612
|
+
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
613
|
+
});
|
|
614
|
+
function bootstrap(object) {
|
|
615
|
+
const breakdown = getOwnPropertyDescriptors(object);
|
|
616
|
+
const control = new Model();
|
|
617
|
+
for (const key in breakdown)
|
|
618
|
+
defineProperty(control, key, breakdown[key]);
|
|
619
|
+
return control;
|
|
620
|
+
}
|
|
621
|
+
function use$1(input, argument) {
|
|
622
|
+
return child(function use(key) {
|
|
623
|
+
const { subject } = this;
|
|
624
|
+
let current;
|
|
625
|
+
const onUpdate = (next) => {
|
|
626
|
+
if (next) {
|
|
627
|
+
current = next instanceof Model
|
|
628
|
+
? next : bootstrap(next);
|
|
629
|
+
Parent.set(current, subject);
|
|
630
|
+
getController(current);
|
|
631
|
+
}
|
|
632
|
+
else
|
|
633
|
+
current = undefined;
|
|
634
|
+
if (typeof argument == "function")
|
|
635
|
+
return argument(current);
|
|
636
|
+
};
|
|
637
|
+
if (input) {
|
|
638
|
+
const initial = Model.isTypeof(input)
|
|
639
|
+
? new input() :
|
|
640
|
+
input instanceof Model
|
|
641
|
+
? input :
|
|
642
|
+
typeof input === "function"
|
|
643
|
+
? input() :
|
|
644
|
+
typeof input === "object"
|
|
645
|
+
? bootstrap(input)
|
|
646
|
+
: null;
|
|
647
|
+
if (initial)
|
|
648
|
+
onUpdate(initial);
|
|
649
|
+
else if (initial === null)
|
|
650
|
+
throw Oops$6.BadArgument(typeof input);
|
|
651
|
+
}
|
|
652
|
+
return {
|
|
653
|
+
get: () => current,
|
|
654
|
+
set: onUpdate
|
|
655
|
+
};
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
function parent(Expects, required) {
|
|
659
|
+
return apply(function parent() {
|
|
660
|
+
const child = this.subject;
|
|
661
|
+
const expected = Expects.name;
|
|
662
|
+
const value = Parent.get(this.subject);
|
|
663
|
+
if (!value) {
|
|
664
|
+
if (required)
|
|
665
|
+
throw Oops$6.ParentRequired(expected, child);
|
|
666
|
+
}
|
|
667
|
+
else if (!(value instanceof Expects))
|
|
668
|
+
throw Oops$6.UnexpectedParent(expected, child, value);
|
|
669
|
+
return { value };
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
281
673
|
const Lifecycle = {
|
|
282
674
|
WILL_RENDER: "willRender",
|
|
283
675
|
WILL_UPDATE: "willUpdate",
|
|
@@ -285,7 +677,7 @@ const Lifecycle = {
|
|
|
285
677
|
WILL_UNMOUNT: "willUnmount",
|
|
286
678
|
DID_MOUNT: "didMount"
|
|
287
679
|
};
|
|
288
|
-
|
|
680
|
+
[
|
|
289
681
|
"didCreate",
|
|
290
682
|
"willDestroy",
|
|
291
683
|
...values(Lifecycle)
|
|
@@ -293,7 +685,7 @@ const lifecycleEvents = [
|
|
|
293
685
|
function lifecycle(prefix) {
|
|
294
686
|
const type = eventsFor(prefix);
|
|
295
687
|
return function useLifecycle(sub, tag) {
|
|
296
|
-
const emit = useMemo(() => {
|
|
688
|
+
const emit = React.useMemo(() => {
|
|
297
689
|
const subject = sub.source;
|
|
298
690
|
const id = typeof tag == "function" ? tag(subject) : tag;
|
|
299
691
|
return (name) => {
|
|
@@ -305,7 +697,7 @@ function lifecycle(prefix) {
|
|
|
305
697
|
emit(sub.active
|
|
306
698
|
? Lifecycle.WILL_UPDATE
|
|
307
699
|
: Lifecycle.WILL_MOUNT);
|
|
308
|
-
useLayoutEffect(() => {
|
|
700
|
+
React.useLayoutEffect(() => {
|
|
309
701
|
sub.commit();
|
|
310
702
|
emit(Lifecycle.DID_MOUNT);
|
|
311
703
|
return () => {
|
|
@@ -319,210 +711,264 @@ function eventsFor(prefix) {
|
|
|
319
711
|
const map = new Map();
|
|
320
712
|
for (const name of values(Lifecycle)) {
|
|
321
713
|
const alias = prefix + name[0].toUpperCase() + name.slice(1);
|
|
322
|
-
lifecycleEvents.push(alias);
|
|
323
714
|
map.set(name, alias);
|
|
324
715
|
}
|
|
325
716
|
return (e) => map.get(e);
|
|
326
717
|
}
|
|
327
718
|
|
|
328
|
-
const
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
const
|
|
332
|
-
|
|
333
|
-
|
|
719
|
+
const useElementLifecycle = lifecycle("element");
|
|
720
|
+
const useComponentLifecycle = lifecycle("component");
|
|
721
|
+
function use(init) {
|
|
722
|
+
const [state, update] = React.useState(() => [
|
|
723
|
+
init(() => update(state.concat()))
|
|
724
|
+
]);
|
|
725
|
+
return state[0];
|
|
334
726
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
const
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
727
|
+
function useTap(model, path, expect) {
|
|
728
|
+
if (typeof path == "function")
|
|
729
|
+
return useComputed(model, path, expect);
|
|
730
|
+
const proxy = useActive(model, path, expect);
|
|
731
|
+
model.update("willRender", true);
|
|
732
|
+
return proxy;
|
|
733
|
+
}
|
|
734
|
+
function useTag(model, id) {
|
|
735
|
+
const hook = use(refresh => (new Subscriber(model, () => refresh)));
|
|
736
|
+
useElementLifecycle(hook, id || 0);
|
|
737
|
+
return hook.proxy;
|
|
738
|
+
}
|
|
739
|
+
function useNew(model, callback) {
|
|
740
|
+
const hook = use(refresh => {
|
|
741
|
+
if (callback)
|
|
742
|
+
callback(model);
|
|
743
|
+
return new Subscriber(model, () => refresh);
|
|
744
|
+
});
|
|
745
|
+
useComponentLifecycle(hook);
|
|
746
|
+
return hook.proxy;
|
|
747
|
+
}
|
|
748
|
+
function usePassive(Type, callback) {
|
|
749
|
+
const instance = React.useMemo(() => {
|
|
750
|
+
const instance = Type.create();
|
|
751
|
+
if (callback)
|
|
752
|
+
callback(instance);
|
|
753
|
+
return instance;
|
|
754
|
+
}, []);
|
|
755
|
+
React.useLayoutEffect(() => () => instance.destroy(), []);
|
|
756
|
+
instance.update("willRender", true);
|
|
757
|
+
return instance;
|
|
758
|
+
}
|
|
759
|
+
function useActive(target, focus, expected) {
|
|
760
|
+
const hook = use(refresh => {
|
|
761
|
+
const sub = new Subscriber(target, () => refresh);
|
|
762
|
+
if (focus) {
|
|
763
|
+
const source = sub.proxy;
|
|
764
|
+
defineProperty(sub, "proxy", {
|
|
765
|
+
get() {
|
|
766
|
+
const value = source[focus];
|
|
767
|
+
if (value === undefined && expected)
|
|
768
|
+
throw suspend(sub.parent, focus);
|
|
769
|
+
return value;
|
|
770
|
+
}
|
|
771
|
+
});
|
|
346
772
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
return placeholder;
|
|
773
|
+
return sub;
|
|
774
|
+
});
|
|
775
|
+
React.useLayoutEffect(() => hook.commit(), []);
|
|
776
|
+
return hook.proxy;
|
|
352
777
|
}
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
778
|
+
function useComputed(target, compute, expected) {
|
|
779
|
+
const hook = use(refresh => {
|
|
780
|
+
const sub = new Subscriber(target, () => update);
|
|
781
|
+
const spy = sub.proxy;
|
|
782
|
+
let value = compute.call(spy, spy);
|
|
783
|
+
let update;
|
|
784
|
+
let retry;
|
|
785
|
+
const set = (next) => {
|
|
786
|
+
value = next;
|
|
787
|
+
if (retry) {
|
|
788
|
+
retry();
|
|
789
|
+
retry = undefined;
|
|
790
|
+
}
|
|
791
|
+
else
|
|
792
|
+
refresh();
|
|
793
|
+
};
|
|
794
|
+
if (value instanceof Promise) {
|
|
795
|
+
value.then(set);
|
|
796
|
+
value = undefined;
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
sub.commit();
|
|
800
|
+
update = () => {
|
|
801
|
+
const next = compute.call(spy, spy);
|
|
802
|
+
if (value != next)
|
|
803
|
+
set(next);
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
const get = expected
|
|
807
|
+
? () => {
|
|
808
|
+
if (value === undefined)
|
|
809
|
+
throw new Promise(res => retry = res);
|
|
810
|
+
return value;
|
|
382
811
|
}
|
|
812
|
+
: () => value;
|
|
813
|
+
defineProperty(sub, "proxy", { get });
|
|
814
|
+
return sub;
|
|
815
|
+
});
|
|
816
|
+
React.useLayoutEffect(() => hook.release, []);
|
|
817
|
+
return hook.proxy;
|
|
818
|
+
}
|
|
819
|
+
function useModel(Type, callback) {
|
|
820
|
+
const hook = use(refresh => {
|
|
821
|
+
const instance = new Type();
|
|
822
|
+
const sub = new Subscriber(instance, () => refresh);
|
|
823
|
+
const release = sub.parent.addListener((key) => {
|
|
824
|
+
if (key == Lifecycle.WILL_UNMOUNT)
|
|
825
|
+
return () => {
|
|
826
|
+
instance.destroy();
|
|
827
|
+
release();
|
|
828
|
+
};
|
|
383
829
|
});
|
|
384
|
-
|
|
830
|
+
if (callback)
|
|
831
|
+
callback(instance);
|
|
832
|
+
return sub;
|
|
833
|
+
});
|
|
834
|
+
useComponentLifecycle(hook);
|
|
835
|
+
usePeerContext(hook.source);
|
|
836
|
+
return hook.proxy;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
class Lookup {
|
|
840
|
+
constructor() {
|
|
841
|
+
this.table = new Map();
|
|
385
842
|
}
|
|
386
|
-
get
|
|
387
|
-
return
|
|
843
|
+
get local() {
|
|
844
|
+
return [
|
|
845
|
+
...new Set(getOwnPropertySymbols(this).map(symbol => this[symbol]))
|
|
846
|
+
];
|
|
388
847
|
}
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const { value } = desc;
|
|
395
|
-
const instruction = Pending.get(value);
|
|
396
|
-
if (instruction) {
|
|
397
|
-
Pending.delete(value);
|
|
398
|
-
delete subject[key];
|
|
399
|
-
instruction.call(this, key, this);
|
|
400
|
-
}
|
|
401
|
-
else if (typeof value !== "function" || /^[A-Z]/.test(key))
|
|
402
|
-
this.manage(key, value);
|
|
403
|
-
}
|
|
848
|
+
key(T) {
|
|
849
|
+
let key = this.table.get(T);
|
|
850
|
+
if (!key) {
|
|
851
|
+
key = Symbol(T.name);
|
|
852
|
+
this.table.set(T, key);
|
|
404
853
|
}
|
|
405
|
-
|
|
406
|
-
return this;
|
|
407
|
-
}
|
|
408
|
-
select(using) {
|
|
409
|
-
const keys = getOwnPropertyNames(this.state);
|
|
410
|
-
return using
|
|
411
|
-
? selectRecursive(using, keys.concat(lifecycleEvents))
|
|
412
|
-
: keys;
|
|
413
|
-
}
|
|
414
|
-
manage(key, initial, effect) {
|
|
415
|
-
const { state, subject } = this;
|
|
416
|
-
state[key] = initial;
|
|
417
|
-
defineProperty(subject, key, {
|
|
418
|
-
enumerable: true,
|
|
419
|
-
configurable: true,
|
|
420
|
-
get: () => state[key],
|
|
421
|
-
set: this.setter(key, effect)
|
|
422
|
-
});
|
|
854
|
+
return key;
|
|
423
855
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
return (value) => {
|
|
427
|
-
if (state[key] == value)
|
|
428
|
-
return;
|
|
429
|
-
if (handler)
|
|
430
|
-
switch (handler.call(subject, value)) {
|
|
431
|
-
case true:
|
|
432
|
-
this.update(key);
|
|
433
|
-
case false:
|
|
434
|
-
return;
|
|
435
|
-
}
|
|
436
|
-
this.update(key, value);
|
|
437
|
-
};
|
|
856
|
+
get(T) {
|
|
857
|
+
return this[this.key(T)];
|
|
438
858
|
}
|
|
439
|
-
|
|
440
|
-
this
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
859
|
+
push(I) {
|
|
860
|
+
const next = create(this);
|
|
861
|
+
if (I instanceof Model || typeof I == "function")
|
|
862
|
+
next.register(I);
|
|
863
|
+
else
|
|
864
|
+
for (const i of values(I))
|
|
865
|
+
next.register(i);
|
|
866
|
+
return next;
|
|
444
867
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
if (
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
setTimeout(() => this.emit(), 0);
|
|
452
|
-
this.frame.add(key);
|
|
453
|
-
for (const subscription of this.followers) {
|
|
454
|
-
const notify = subscription(key, this);
|
|
455
|
-
if (notify)
|
|
456
|
-
this.waiting.add(notify);
|
|
868
|
+
register(I) {
|
|
869
|
+
let writable = true;
|
|
870
|
+
let T;
|
|
871
|
+
if (I instanceof Model) {
|
|
872
|
+
T = I.constructor;
|
|
873
|
+
writable = false;
|
|
457
874
|
}
|
|
875
|
+
else {
|
|
876
|
+
T = I;
|
|
877
|
+
I = I.create();
|
|
878
|
+
}
|
|
879
|
+
do {
|
|
880
|
+
const key = this.key(T);
|
|
881
|
+
const conflict = this.hasOwnProperty(key);
|
|
882
|
+
defineProperty(this, key, {
|
|
883
|
+
value: conflict ? null : I,
|
|
884
|
+
configurable: true,
|
|
885
|
+
writable
|
|
886
|
+
});
|
|
887
|
+
T = getPrototypeOf(T);
|
|
888
|
+
} while (T !== Model);
|
|
889
|
+
return I;
|
|
458
890
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
this.frame.clear();
|
|
466
|
-
handle.forEach(callback => {
|
|
467
|
-
try {
|
|
468
|
-
callback(handled);
|
|
469
|
-
}
|
|
470
|
-
catch (e) { }
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
function keys(from, using) {
|
|
475
|
-
if (typeof using == "string")
|
|
476
|
-
return [using];
|
|
477
|
-
if (typeof using == "object") {
|
|
478
|
-
using = Array.from(using);
|
|
479
|
-
if (using.length === 0)
|
|
480
|
-
using = undefined;
|
|
481
|
-
else
|
|
482
|
-
return using;
|
|
891
|
+
pop() {
|
|
892
|
+
for (const key of getOwnPropertySymbols(this)) {
|
|
893
|
+
const entry = getOwnPropertyDescriptor(this, key);
|
|
894
|
+
if (entry.writable)
|
|
895
|
+
entry.value.destroy();
|
|
896
|
+
}
|
|
483
897
|
}
|
|
484
|
-
return from.select(using);
|
|
485
898
|
}
|
|
486
899
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
if (
|
|
519
|
-
|
|
520
|
-
|
|
900
|
+
const Oops$5 = issues({
|
|
901
|
+
NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
|
|
902
|
+
NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
|
|
903
|
+
BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
904
|
+
});
|
|
905
|
+
const LookupContext = React.createContext(new Lookup());
|
|
906
|
+
const useLookup = () => React.useContext(LookupContext);
|
|
907
|
+
function useContext(Type, strict) {
|
|
908
|
+
const instance = useLookup().get(Type);
|
|
909
|
+
if (!instance && strict)
|
|
910
|
+
throw Oops$5.NothingInContext(Type.name);
|
|
911
|
+
return instance;
|
|
912
|
+
}
|
|
913
|
+
function Consumer(props) {
|
|
914
|
+
const { get, has, children, of: Control } = props;
|
|
915
|
+
if (typeof children == "function")
|
|
916
|
+
return children(useTap(useContext(Control)));
|
|
917
|
+
const callback = has || get;
|
|
918
|
+
if (typeof callback == "function")
|
|
919
|
+
callback(useContext(Control, !!has));
|
|
920
|
+
else
|
|
921
|
+
throw Oops$5.BadConsumerProps();
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
function useNewContext(inject) {
|
|
925
|
+
const from = useLookup();
|
|
926
|
+
return React.useMemo(() => {
|
|
927
|
+
if (!inject)
|
|
928
|
+
throw Oops$5.NoProviderType();
|
|
929
|
+
const context = from.push(inject);
|
|
930
|
+
for (const instance of context.local)
|
|
931
|
+
if (instance)
|
|
932
|
+
for (const apply of getPending(instance))
|
|
933
|
+
apply(context);
|
|
934
|
+
return context;
|
|
935
|
+
}, []);
|
|
936
|
+
}
|
|
937
|
+
function useAppliedProps(within, props) {
|
|
938
|
+
const update = React.useMemo(() => {
|
|
939
|
+
const targets = within.local;
|
|
940
|
+
return function integrate(props) {
|
|
941
|
+
for (const [key, value] of entries(props))
|
|
942
|
+
if (key != "of" && key != "children")
|
|
943
|
+
for (const into of targets)
|
|
944
|
+
if (into && key in into)
|
|
945
|
+
into[key] = value;
|
|
521
946
|
};
|
|
522
|
-
},
|
|
947
|
+
}, []);
|
|
948
|
+
update(props);
|
|
949
|
+
}
|
|
950
|
+
function RenderFunction(props) {
|
|
951
|
+
const hook = use(refresh => {
|
|
952
|
+
const targets = props.context.local;
|
|
953
|
+
if (targets.length == 1)
|
|
954
|
+
return new Subscriber(targets[0], () => refresh);
|
|
955
|
+
return {};
|
|
956
|
+
});
|
|
957
|
+
if (hook.commit)
|
|
958
|
+
React.useLayoutEffect(() => hook.commit(), []);
|
|
959
|
+
return props.render(hook.proxy);
|
|
960
|
+
}
|
|
961
|
+
function Provider(props) {
|
|
962
|
+
const context = useNewContext(props.of);
|
|
963
|
+
const render = props.children;
|
|
964
|
+
useAppliedProps(context, props);
|
|
965
|
+
React.useLayoutEffect(() => () => context.pop(), []);
|
|
966
|
+
return React.createElement(LookupContext.Provider, { value: context }, typeof render == "function"
|
|
967
|
+
? React.createElement(RenderFunction, { context, render })
|
|
968
|
+
: render);
|
|
523
969
|
}
|
|
524
970
|
|
|
525
|
-
const Oops$
|
|
971
|
+
const Oops$4 = issues({
|
|
526
972
|
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
527
973
|
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.`
|
|
528
974
|
});
|
|
@@ -530,14 +976,16 @@ const PendingContext = new WeakMap();
|
|
|
530
976
|
const ContextWasUsed = new WeakMap();
|
|
531
977
|
function tap(type, argument) {
|
|
532
978
|
return child(function tap(key) {
|
|
533
|
-
return
|
|
979
|
+
return {
|
|
980
|
+
get: pendingAccess(this.subject, type, key, argument)
|
|
981
|
+
};
|
|
534
982
|
});
|
|
535
983
|
}
|
|
536
984
|
function pendingAccess(from, type, key, argument) {
|
|
537
|
-
if ("
|
|
538
|
-
return () => type.
|
|
539
|
-
if ("
|
|
540
|
-
throw Oops$
|
|
985
|
+
if ("set" in type)
|
|
986
|
+
return () => type.get();
|
|
987
|
+
if ("set" in from.constructor)
|
|
988
|
+
throw Oops$4.CantAttachGlobal(from, type.name);
|
|
541
989
|
let instance;
|
|
542
990
|
getPending(from).push(context => {
|
|
543
991
|
instance = context.get(type);
|
|
@@ -546,7 +994,7 @@ function pendingAccess(from, type, key, argument) {
|
|
|
546
994
|
instance = undefined;
|
|
547
995
|
}
|
|
548
996
|
else if (!instance && argument)
|
|
549
|
-
throw Oops$
|
|
997
|
+
throw Oops$4.AmbientRequired(type.name, from, key);
|
|
550
998
|
});
|
|
551
999
|
return () => instance;
|
|
552
1000
|
}
|
|
@@ -572,7 +1020,7 @@ function getPending(subject) {
|
|
|
572
1020
|
return pending;
|
|
573
1021
|
}
|
|
574
1022
|
|
|
575
|
-
const Oops$
|
|
1023
|
+
const Oops$3 = issues({
|
|
576
1024
|
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
|
|
577
1025
|
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
578
1026
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
@@ -589,7 +1037,7 @@ function ref(arg) {
|
|
|
589
1037
|
return apply(function ref(key) {
|
|
590
1038
|
let value = {};
|
|
591
1039
|
if (typeof arg == "object") {
|
|
592
|
-
const source =
|
|
1040
|
+
const source = getController(arg);
|
|
593
1041
|
for (const key in source.state)
|
|
594
1042
|
defineLazy(value, key, createRef.bind(source, key));
|
|
595
1043
|
}
|
|
@@ -603,7 +1051,7 @@ function act(task) {
|
|
|
603
1051
|
let pending = false;
|
|
604
1052
|
const invoke = (...args) => {
|
|
605
1053
|
if (pending)
|
|
606
|
-
return Promise.reject(Oops$
|
|
1054
|
+
return Promise.reject(Oops$3.DuplicateAction(key));
|
|
607
1055
|
pending = true;
|
|
608
1056
|
this.update(key);
|
|
609
1057
|
return new Promise(res => {
|
|
@@ -624,16 +1072,19 @@ function act(task) {
|
|
|
624
1072
|
};
|
|
625
1073
|
});
|
|
626
1074
|
}
|
|
627
|
-
function from(source, setter,
|
|
1075
|
+
function from(source, setter, argument) {
|
|
628
1076
|
return apply(function from(key) {
|
|
629
|
-
const { subject } = this;
|
|
630
1077
|
let getSource;
|
|
1078
|
+
const { subject } = this;
|
|
1079
|
+
const getter = argument === true
|
|
1080
|
+
? pendingValue
|
|
1081
|
+
: argument || undefined;
|
|
631
1082
|
// Easy mistake, using a peer, will always be unresolved.
|
|
632
1083
|
if (typeof source == "symbol")
|
|
633
|
-
throw Oops$
|
|
1084
|
+
throw Oops$3.PeerNotAllowed(subject, key);
|
|
634
1085
|
// replace source controller in-case different
|
|
635
1086
|
if (typeof source == "object")
|
|
636
|
-
getSource = () =>
|
|
1087
|
+
getSource = () => getController(source);
|
|
637
1088
|
// specifically an arrow function (getter factory)
|
|
638
1089
|
else if (!source.prototype) {
|
|
639
1090
|
setter = source.call(subject, key);
|
|
@@ -642,22 +1093,24 @@ function from(source, setter, getter) {
|
|
|
642
1093
|
// is a peer Model (constructor)
|
|
643
1094
|
else if (Model.isTypeof(source))
|
|
644
1095
|
getSource = pendingAccess(subject, source, key, true);
|
|
645
|
-
// Regular function is
|
|
1096
|
+
// Regular function is too ambiguous so not allowed.
|
|
646
1097
|
else
|
|
647
|
-
throw Oops$
|
|
1098
|
+
throw Oops$3.BadComputedSource(subject, key, source);
|
|
648
1099
|
prepare(this, key, getSource, setter, getter);
|
|
649
1100
|
});
|
|
650
1101
|
}
|
|
651
1102
|
|
|
652
|
-
const Oops$
|
|
1103
|
+
const Oops$2 = issues({
|
|
653
1104
|
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
654
1105
|
});
|
|
1106
|
+
/* deprecated - ignore coverage */
|
|
1107
|
+
/* istanbul ignore next */
|
|
655
1108
|
function pending(source, compute) {
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
1109
|
+
if (source === undefined)
|
|
1110
|
+
return set();
|
|
1111
|
+
if (typeof source == "function" && !source.prototype)
|
|
1112
|
+
return set(source);
|
|
1113
|
+
return from(source, compute, true);
|
|
661
1114
|
}
|
|
662
1115
|
/**
|
|
663
1116
|
* Get value, suspend instead if undefined.
|
|
@@ -671,8 +1124,42 @@ function pendingValue(via, key) {
|
|
|
671
1124
|
throw suspend(via, key);
|
|
672
1125
|
return value;
|
|
673
1126
|
}
|
|
1127
|
+
function pendingFactory(via, key, fn) {
|
|
1128
|
+
const { subject, state } = via;
|
|
1129
|
+
let waiting;
|
|
1130
|
+
let error;
|
|
1131
|
+
return () => {
|
|
1132
|
+
if (waiting)
|
|
1133
|
+
throw waiting;
|
|
1134
|
+
if (error)
|
|
1135
|
+
throw error;
|
|
1136
|
+
if (key in state)
|
|
1137
|
+
return state[key];
|
|
1138
|
+
let output;
|
|
1139
|
+
try {
|
|
1140
|
+
output = fn.call(subject, key, subject);
|
|
1141
|
+
}
|
|
1142
|
+
catch (err) {
|
|
1143
|
+
throw error = err;
|
|
1144
|
+
}
|
|
1145
|
+
if (output instanceof Promise) {
|
|
1146
|
+
const issue = Oops$2.ValueNotReady(subject, key);
|
|
1147
|
+
output
|
|
1148
|
+
.catch(err => error = err)
|
|
1149
|
+
.then(out => state[key] = out)
|
|
1150
|
+
.finally(() => waiting = undefined);
|
|
1151
|
+
throw waiting = Object.assign(output, {
|
|
1152
|
+
message: issue.message,
|
|
1153
|
+
stack: issue.stack
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
else {
|
|
1157
|
+
return state[key] = output;
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
674
1161
|
function suspend(source, key) {
|
|
675
|
-
const error = Oops$
|
|
1162
|
+
const error = Oops$2.ValueNotReady(source.subject, key);
|
|
676
1163
|
const promise = new Promise(resolve => {
|
|
677
1164
|
const release = source.addListener(forKey => {
|
|
678
1165
|
if (forKey == key)
|
|
@@ -690,423 +1177,87 @@ function suspend(source, key) {
|
|
|
690
1177
|
message: error.message,
|
|
691
1178
|
stack: error.stack
|
|
692
1179
|
});
|
|
693
|
-
}
|
|
694
|
-
function suspendForComputed(source, compute) {
|
|
695
|
-
function getter(_value, key) {
|
|
696
|
-
return pendingValue(manage(this), key);
|
|
697
|
-
}
|
|
698
|
-
return from(source, compute, getter);
|
|
699
|
-
}
|
|
700
|
-
function suspendForValue() {
|
|
701
|
-
return apply(function pending(key) {
|
|
702
|
-
this.state[key] = undefined;
|
|
703
|
-
return {
|
|
704
|
-
set: this.setter(key),
|
|
705
|
-
get: () => pendingValue(this, key)
|
|
706
|
-
};
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
function suspendForAsync(source) {
|
|
710
|
-
return apply(function suspense(key) {
|
|
711
|
-
const subject = this.subject;
|
|
712
|
-
let waiting = true;
|
|
713
|
-
let value;
|
|
714
|
-
let error;
|
|
715
|
-
return () => {
|
|
716
|
-
if (error)
|
|
717
|
-
throw error;
|
|
718
|
-
if (!waiting)
|
|
719
|
-
return value;
|
|
720
|
-
const issue = Oops$4.ValueNotReady(subject, key);
|
|
721
|
-
let suspend = source
|
|
722
|
-
.call(subject, key)
|
|
723
|
-
.catch(err => error = err)
|
|
724
|
-
.then(out => value = out)
|
|
725
|
-
.finally(() => waiting = false);
|
|
726
|
-
throw Object.assign(suspend, {
|
|
727
|
-
message: issue.message,
|
|
728
|
-
stack: issue.stack
|
|
729
|
-
});
|
|
730
|
-
};
|
|
731
|
-
});
|
|
732
1180
|
}
|
|
733
1181
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
function
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
return instance;
|
|
746
|
-
}, []);
|
|
747
|
-
useLayoutEffect(() => () => instance.destroy(), []);
|
|
748
|
-
return instance;
|
|
749
|
-
}
|
|
750
|
-
function useWatcher(target, focus, expected) {
|
|
751
|
-
const hook = use$1(refresh => {
|
|
752
|
-
const sub = new Subscriber(target, () => refresh);
|
|
753
|
-
if (focus) {
|
|
754
|
-
const source = sub.proxy;
|
|
755
|
-
defineProperty(sub, "proxy", {
|
|
756
|
-
get() {
|
|
757
|
-
const value = source[focus];
|
|
758
|
-
if (value === undefined && expected)
|
|
759
|
-
throw suspend(sub.parent, focus);
|
|
760
|
-
return value;
|
|
761
|
-
}
|
|
762
|
-
});
|
|
763
|
-
}
|
|
764
|
-
return sub;
|
|
765
|
-
});
|
|
766
|
-
useLayoutEffect(() => hook.commit(), []);
|
|
767
|
-
return hook.proxy;
|
|
768
|
-
}
|
|
769
|
-
function useComputed(target, compute, expected) {
|
|
770
|
-
const hook = use$1(refresh => {
|
|
771
|
-
const sub = new Subscriber(target, () => update);
|
|
772
|
-
const { proxy } = sub;
|
|
773
|
-
let value;
|
|
774
|
-
let retry;
|
|
775
|
-
const update = () => {
|
|
776
|
-
const next = compute.call(proxy, proxy);
|
|
777
|
-
if (value == next)
|
|
778
|
-
return;
|
|
779
|
-
value = next;
|
|
780
|
-
if (retry) {
|
|
781
|
-
retry();
|
|
782
|
-
retry = undefined;
|
|
783
|
-
}
|
|
784
|
-
else
|
|
785
|
-
refresh();
|
|
786
|
-
};
|
|
787
|
-
const access = () => {
|
|
788
|
-
if (value === undefined && expected)
|
|
789
|
-
throw new Promise(res => {
|
|
790
|
-
retry = res;
|
|
791
|
-
});
|
|
792
|
-
return value;
|
|
793
|
-
};
|
|
794
|
-
value = compute.call(proxy, proxy);
|
|
795
|
-
sub.commit();
|
|
796
|
-
defineProperty(sub, "proxy", { get: access });
|
|
797
|
-
return sub;
|
|
798
|
-
});
|
|
799
|
-
useLayoutEffect(() => hook.release, []);
|
|
800
|
-
return hook.proxy;
|
|
801
|
-
}
|
|
802
|
-
function useModel(Type, callback) {
|
|
803
|
-
const hook = use$1(refresh => {
|
|
804
|
-
const instance = new Type();
|
|
805
|
-
const control = manage(instance);
|
|
806
|
-
const sub = new Subscriber(control, () => refresh);
|
|
807
|
-
const release = control.addListener((key) => {
|
|
808
|
-
if (key == Lifecycle.WILL_UNMOUNT)
|
|
809
|
-
return () => {
|
|
810
|
-
instance.destroy();
|
|
811
|
-
release();
|
|
812
|
-
};
|
|
1182
|
+
const Oops$1 = issues({
|
|
1183
|
+
NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
|
|
1184
|
+
BadFactory: () => `Set instruction can only accept a factory or undefined.`,
|
|
1185
|
+
FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
1186
|
+
});
|
|
1187
|
+
function lazy(value) {
|
|
1188
|
+
return apply(function lazy(key) {
|
|
1189
|
+
const source = this.subject;
|
|
1190
|
+
source[key] = value;
|
|
1191
|
+
defineProperty(this.state, key, {
|
|
1192
|
+
get: () => source[key]
|
|
813
1193
|
});
|
|
814
|
-
if (callback)
|
|
815
|
-
callback(instance);
|
|
816
|
-
return sub;
|
|
817
1194
|
});
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
key(T) {
|
|
829
|
-
let key = this.table.get(T);
|
|
830
|
-
if (!key) {
|
|
831
|
-
key = Symbol(T.name);
|
|
832
|
-
this.table.set(T, key);
|
|
833
|
-
}
|
|
834
|
-
return key;
|
|
835
|
-
}
|
|
836
|
-
get(T) {
|
|
837
|
-
return this[this.key(T)];
|
|
838
|
-
}
|
|
839
|
-
push(I) {
|
|
840
|
-
const next = create(this);
|
|
841
|
-
if (I instanceof Model || typeof I == "function")
|
|
842
|
-
next.register(I);
|
|
843
|
-
else
|
|
844
|
-
for (const i of values(I))
|
|
845
|
-
next.register(i);
|
|
846
|
-
return next;
|
|
847
|
-
}
|
|
848
|
-
register(I) {
|
|
849
|
-
let writable = true;
|
|
850
|
-
let T;
|
|
851
|
-
if (I instanceof Model) {
|
|
852
|
-
T = I.constructor;
|
|
853
|
-
writable = false;
|
|
854
|
-
}
|
|
1195
|
+
}
|
|
1196
|
+
function set(factory, argument) {
|
|
1197
|
+
return apply(function set(key) {
|
|
1198
|
+
let set;
|
|
1199
|
+
let get;
|
|
1200
|
+
const required = argument === true || argument === undefined;
|
|
1201
|
+
if (factory === undefined)
|
|
1202
|
+
get = () => pendingValue(this, key);
|
|
1203
|
+
else if (typeof factory !== "function")
|
|
1204
|
+
throw Oops$1.BadFactory();
|
|
855
1205
|
else {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
const entry = getOwnPropertyDescriptor(this, key);
|
|
870
|
-
if (entry.writable)
|
|
871
|
-
entry.value.destroy();
|
|
1206
|
+
get = pendingFactory(this, key, factory);
|
|
1207
|
+
if (required)
|
|
1208
|
+
try {
|
|
1209
|
+
get();
|
|
1210
|
+
}
|
|
1211
|
+
catch (err) {
|
|
1212
|
+
if (err instanceof Promise)
|
|
1213
|
+
;
|
|
1214
|
+
else {
|
|
1215
|
+
Oops$1.FactoryFailed(this.subject, key).warn();
|
|
1216
|
+
throw err;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
872
1219
|
}
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
}
|
|
881
|
-
const LookupContext = createContext(new Lookup());
|
|
882
|
-
const useLookup = () => useContext(LookupContext);
|
|
883
|
-
function useFromContext(Type, strict) {
|
|
884
|
-
const instance = useLookup().get(Type);
|
|
885
|
-
if (!instance && strict)
|
|
886
|
-
throw Oops$3.NothingInContext(Type.name);
|
|
887
|
-
return instance;
|
|
888
|
-
}
|
|
889
|
-
function Consumer(props) {
|
|
890
|
-
const { get, has, children, of: Control } = props;
|
|
891
|
-
if (typeof children == "function")
|
|
892
|
-
return children(Control.tap());
|
|
893
|
-
const callback = has || get;
|
|
894
|
-
if (typeof callback == "function")
|
|
895
|
-
callback(Control.get(!!has));
|
|
896
|
-
else
|
|
897
|
-
throw Oops$3.BadConsumerProps();
|
|
898
|
-
return null;
|
|
899
|
-
}
|
|
900
|
-
function useNewContext(from, inject) {
|
|
901
|
-
return useMemo(() => {
|
|
902
|
-
if (!inject)
|
|
903
|
-
throw Oops$3.NoProviderType();
|
|
904
|
-
const context = from.push(inject);
|
|
905
|
-
for (const instance of context.local)
|
|
906
|
-
for (const apply of getPending(instance))
|
|
907
|
-
apply(context);
|
|
908
|
-
return context;
|
|
909
|
-
}, []);
|
|
910
|
-
}
|
|
911
|
-
function useAppliedProps(within, props) {
|
|
912
|
-
const update = useMemo(() => {
|
|
913
|
-
const targets = within.local;
|
|
914
|
-
return function integrate(props) {
|
|
915
|
-
for (const [key, value] of entries(props))
|
|
916
|
-
if (key != "of" && key != "children")
|
|
917
|
-
for (const into of targets)
|
|
918
|
-
if (key in into)
|
|
919
|
-
into[key] = value;
|
|
920
|
-
};
|
|
921
|
-
}, []);
|
|
922
|
-
update(props);
|
|
923
|
-
}
|
|
924
|
-
function RenderFunction(props) {
|
|
925
|
-
const hook = use$1(refresh => {
|
|
926
|
-
const targets = props.context.local;
|
|
927
|
-
if (targets.length == 1)
|
|
928
|
-
return new Subscriber(targets[0], () => refresh);
|
|
929
|
-
return {};
|
|
1220
|
+
if (typeof argument == "function")
|
|
1221
|
+
set = createValueEffect(argument);
|
|
1222
|
+
else
|
|
1223
|
+
set = (value) => {
|
|
1224
|
+
if (value === undefined && required)
|
|
1225
|
+
throw Oops$1.NonOptional(this.subject, key);
|
|
1226
|
+
};
|
|
1227
|
+
return { set, get };
|
|
930
1228
|
});
|
|
931
|
-
if (hook.commit)
|
|
932
|
-
useLayoutEffect(() => hook.commit(), []);
|
|
933
|
-
return props.render(hook.proxy);
|
|
934
1229
|
}
|
|
935
|
-
function
|
|
936
|
-
|
|
937
|
-
const current = useLookup();
|
|
938
|
-
const context = useNewContext(current, props.of);
|
|
939
|
-
useAppliedProps(context, props);
|
|
940
|
-
useLayoutEffect(() => () => context.pop(), []);
|
|
941
|
-
return createElement(LookupContext.Provider, { value: context }, typeof render == "function"
|
|
942
|
-
? createElement(RenderFunction, { context, render })
|
|
943
|
-
: render);
|
|
1230
|
+
function on(initial, onUpdate) {
|
|
1231
|
+
return set(initial && (() => initial), onUpdate);
|
|
944
1232
|
}
|
|
945
1233
|
|
|
946
|
-
|
|
947
|
-
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
948
|
-
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
949
|
-
});
|
|
950
|
-
const useElementLifecycle = lifecycle("element");
|
|
951
|
-
const useComponentLifecycle = lifecycle("component");
|
|
952
|
-
class Model {
|
|
953
|
-
constructor() {
|
|
954
|
-
const control = Controller.setup(this);
|
|
955
|
-
define(this, "get", this);
|
|
956
|
-
define(this, "set", this);
|
|
957
|
-
defer(control, "on");
|
|
958
|
-
defer(control, "effect");
|
|
959
|
-
control.waiting.add(() => {
|
|
960
|
-
delete this.on;
|
|
961
|
-
delete this.effect;
|
|
962
|
-
});
|
|
963
|
-
}
|
|
1234
|
+
class MVC extends Model {
|
|
964
1235
|
tap(path, expect) {
|
|
965
|
-
|
|
966
|
-
return useComputed(this, path, expect);
|
|
967
|
-
const proxy = useWatcher(this, path, expect);
|
|
968
|
-
this.update("willRender", true);
|
|
969
|
-
return proxy;
|
|
1236
|
+
return useTap(this, path, expect);
|
|
970
1237
|
}
|
|
971
1238
|
tag(id) {
|
|
972
|
-
|
|
973
|
-
return new Subscriber(this, () => refresh);
|
|
974
|
-
});
|
|
975
|
-
useElementLifecycle(hook, id || 0);
|
|
976
|
-
return hook.proxy;
|
|
1239
|
+
return useTag(this, id);
|
|
977
1240
|
}
|
|
978
1241
|
use(callback) {
|
|
979
|
-
|
|
980
|
-
if (callback)
|
|
981
|
-
callback(this);
|
|
982
|
-
return new Subscriber(this, () => refresh);
|
|
983
|
-
});
|
|
984
|
-
useComponentLifecycle(hook);
|
|
985
|
-
return hook.proxy;
|
|
986
|
-
}
|
|
987
|
-
on(subset, handler, squash, once) {
|
|
988
|
-
const control = manage(this);
|
|
989
|
-
const request = keys(control, subset);
|
|
990
|
-
const callback = squash
|
|
991
|
-
? handler.bind(this)
|
|
992
|
-
: frame => frame
|
|
993
|
-
.filter(k => request.includes(k))
|
|
994
|
-
.forEach(k => handler.call(this, control.state[k], k));
|
|
995
|
-
const trigger = once
|
|
996
|
-
? frame => { remove(); callback(frame); }
|
|
997
|
-
: callback;
|
|
998
|
-
ensure(control, request);
|
|
999
|
-
const remove = control.addListener(key => {
|
|
1000
|
-
if (request.includes(key))
|
|
1001
|
-
return trigger;
|
|
1002
|
-
});
|
|
1003
|
-
return remove;
|
|
1004
|
-
}
|
|
1005
|
-
once(select, callback, squash) {
|
|
1006
|
-
if (callback)
|
|
1007
|
-
return this.on(select, callback, squash, true);
|
|
1008
|
-
else
|
|
1009
|
-
return new Promise(resolve => {
|
|
1010
|
-
this.on(select, resolve, true, true);
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
|
-
effect(callback, select) {
|
|
1014
|
-
const control = manage(this);
|
|
1015
|
-
let target = this;
|
|
1016
|
-
const effect = createEffect(callback);
|
|
1017
|
-
const invoke = () => effect.call(target, target);
|
|
1018
|
-
if (select) {
|
|
1019
|
-
invoke();
|
|
1020
|
-
return this.on(select, invoke, true);
|
|
1021
|
-
}
|
|
1022
|
-
else {
|
|
1023
|
-
const sub = new Subscriber(control, () => invoke);
|
|
1024
|
-
target = sub.proxy;
|
|
1025
|
-
invoke();
|
|
1026
|
-
return sub.commit();
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
import(from, subset) {
|
|
1030
|
-
for (const key of keys(manage(this), subset))
|
|
1031
|
-
if (key in from)
|
|
1032
|
-
this[key] = from[key];
|
|
1033
|
-
}
|
|
1034
|
-
export(subset) {
|
|
1035
|
-
const control = manage(this);
|
|
1036
|
-
const output = {};
|
|
1037
|
-
for (const key of keys(control, subset))
|
|
1038
|
-
output[key] = control.state[key];
|
|
1039
|
-
return output;
|
|
1040
|
-
}
|
|
1041
|
-
update(arg, tag) {
|
|
1042
|
-
const control = manage(this);
|
|
1043
|
-
if (typeof arg == "function")
|
|
1044
|
-
arg = select(this, arg);
|
|
1045
|
-
if (typeof arg == "boolean") {
|
|
1046
|
-
if (!control.pending === arg)
|
|
1047
|
-
return Promise.reject(Oops$2.StrictUpdate(arg));
|
|
1048
|
-
}
|
|
1049
|
-
else if (arg) {
|
|
1050
|
-
control.update(arg);
|
|
1051
|
-
if (1 in arguments && arg in this) {
|
|
1052
|
-
const method = this[arg];
|
|
1053
|
-
if (typeof method == "function")
|
|
1054
|
-
if (typeof tag != "boolean")
|
|
1055
|
-
method.call(this, tag);
|
|
1056
|
-
else if (tag)
|
|
1057
|
-
method.call(this);
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
return {
|
|
1061
|
-
then(callback) {
|
|
1062
|
-
if (callback)
|
|
1063
|
-
if (control.pending)
|
|
1064
|
-
control.waiting.add(callback);
|
|
1065
|
-
else
|
|
1066
|
-
callback(false);
|
|
1067
|
-
else
|
|
1068
|
-
throw Oops$2.NoChaining();
|
|
1069
|
-
}
|
|
1070
|
-
};
|
|
1071
|
-
}
|
|
1072
|
-
destroy() {
|
|
1073
|
-
this.update("willDestroy", true);
|
|
1074
|
-
}
|
|
1075
|
-
toString() {
|
|
1076
|
-
return this.constructor.name;
|
|
1077
|
-
}
|
|
1078
|
-
static create(...args) {
|
|
1079
|
-
const instance = new this(...args);
|
|
1080
|
-
manage(instance);
|
|
1081
|
-
return instance;
|
|
1242
|
+
return useNew(this, callback);
|
|
1082
1243
|
}
|
|
1083
1244
|
static new(callback) {
|
|
1084
|
-
|
|
1085
|
-
instance.update("willRender", true);
|
|
1086
|
-
return instance;
|
|
1087
|
-
}
|
|
1088
|
-
static find(strict) {
|
|
1089
|
-
return useFromContext(this, strict);
|
|
1245
|
+
return usePassive(this, callback);
|
|
1090
1246
|
}
|
|
1091
1247
|
static get(key) {
|
|
1092
|
-
const instance = this
|
|
1093
|
-
return (typeof key == "
|
|
1094
|
-
key
|
|
1095
|
-
|
|
1096
|
-
instance[key] :
|
|
1097
|
-
instance);
|
|
1248
|
+
const instance = useContext(this, key !== false);
|
|
1249
|
+
return (typeof key == "string" ?
|
|
1250
|
+
instance[key] :
|
|
1251
|
+
instance);
|
|
1098
1252
|
}
|
|
1099
1253
|
static tap(key, expect) {
|
|
1100
|
-
return this.
|
|
1254
|
+
return this.get().tap(key, expect);
|
|
1101
1255
|
}
|
|
1102
1256
|
static tag(id) {
|
|
1103
|
-
return this.
|
|
1257
|
+
return this.get().tag(id);
|
|
1104
1258
|
}
|
|
1105
1259
|
static use(callback) {
|
|
1106
|
-
|
|
1107
|
-
useComponentLifecycle(instance[LOCAL]);
|
|
1108
|
-
usePeerContext(instance.get);
|
|
1109
|
-
return instance;
|
|
1260
|
+
return useModel(this, callback);
|
|
1110
1261
|
}
|
|
1111
1262
|
static uses(props, only) {
|
|
1112
1263
|
return this.use(instance => {
|
|
@@ -1118,131 +1269,11 @@ class Model {
|
|
|
1118
1269
|
instance.import(props, only);
|
|
1119
1270
|
return instance;
|
|
1120
1271
|
}
|
|
1121
|
-
static meta(path) {
|
|
1272
|
+
static meta(path, expect) {
|
|
1122
1273
|
return typeof path == "function"
|
|
1123
|
-
? useComputed(this, path)
|
|
1124
|
-
:
|
|
1274
|
+
? useComputed(this, path, expect)
|
|
1275
|
+
: useActive(this, path, expect);
|
|
1125
1276
|
}
|
|
1126
|
-
static isTypeof(maybe) {
|
|
1127
|
-
return (typeof maybe == "function" &&
|
|
1128
|
-
maybe.prototype instanceof this);
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
Model.CONTROL = CONTROL;
|
|
1132
|
-
Model.STATE = STATE;
|
|
1133
|
-
Model.LOCAL = LOCAL;
|
|
1134
|
-
Model.WHY = UPDATE;
|
|
1135
|
-
defineLazy(Model, CONTROL, function () {
|
|
1136
|
-
return new Controller(this).start();
|
|
1137
|
-
});
|
|
1138
|
-
function defer(on, method) {
|
|
1139
|
-
const { subject, waiting } = on;
|
|
1140
|
-
const real = subject[method];
|
|
1141
|
-
subject[method] = (...args) => {
|
|
1142
|
-
let done;
|
|
1143
|
-
waiting.add(() => {
|
|
1144
|
-
done = real.apply(subject, args);
|
|
1145
|
-
});
|
|
1146
|
-
return () => done();
|
|
1147
|
-
};
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1150
|
-
const Parent = new WeakMap();
|
|
1151
|
-
const Oops$1 = issues({
|
|
1152
|
-
ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
1153
|
-
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
1154
|
-
UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
|
|
1155
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1156
|
-
IsReadOnly: (owner, key) => `${owner}.${key} is set to read-only, but tried to reassign assign.`,
|
|
1157
|
-
MustBeDefined: (owner, key) => `${owner}.${key} must have initial value, as a read-only property.`
|
|
1158
|
-
});
|
|
1159
|
-
function bootstrap(object) {
|
|
1160
|
-
const breakdown = getOwnPropertyDescriptors(object);
|
|
1161
|
-
const control = new Model();
|
|
1162
|
-
for (const key in breakdown)
|
|
1163
|
-
defineProperty(control, key, breakdown[key]);
|
|
1164
|
-
return control;
|
|
1165
|
-
}
|
|
1166
|
-
function use(input, argument) {
|
|
1167
|
-
return child(function use(key) {
|
|
1168
|
-
const { subject } = this;
|
|
1169
|
-
// `true` => readonly
|
|
1170
|
-
// `false` => writable, may be undefined
|
|
1171
|
-
// `undefined` => writable (default)
|
|
1172
|
-
let mode = argument;
|
|
1173
|
-
let current;
|
|
1174
|
-
const onUpdate = (next, initial) => {
|
|
1175
|
-
if (mode === true && !initial)
|
|
1176
|
-
throw Oops$1.IsReadOnly(subject, key);
|
|
1177
|
-
if (next) {
|
|
1178
|
-
current = next instanceof Model
|
|
1179
|
-
? next : bootstrap(next);
|
|
1180
|
-
Parent.set(current, subject);
|
|
1181
|
-
manage(current);
|
|
1182
|
-
}
|
|
1183
|
-
else if (mode === undefined)
|
|
1184
|
-
throw Oops$1.UndefinedNotAllowed(key);
|
|
1185
|
-
else
|
|
1186
|
-
current = undefined;
|
|
1187
|
-
if (typeof argument == "function")
|
|
1188
|
-
return argument(current);
|
|
1189
|
-
};
|
|
1190
|
-
if (input) {
|
|
1191
|
-
current =
|
|
1192
|
-
Model.isTypeof(input) ? new input() :
|
|
1193
|
-
input instanceof Model ? input :
|
|
1194
|
-
typeof input === "function" ? input() :
|
|
1195
|
-
typeof input === "object" ? bootstrap(input) :
|
|
1196
|
-
Oops$1.BadArgument(typeof input).throw();
|
|
1197
|
-
if (current)
|
|
1198
|
-
mode = onUpdate(current, true) || mode;
|
|
1199
|
-
else if (mode == true)
|
|
1200
|
-
throw Oops$1.MustBeDefined(subject, key);
|
|
1201
|
-
}
|
|
1202
|
-
else
|
|
1203
|
-
mode = false;
|
|
1204
|
-
this.manage(key, current, onUpdate);
|
|
1205
|
-
return () => current;
|
|
1206
|
-
});
|
|
1207
|
-
}
|
|
1208
|
-
function parent(Expects, required) {
|
|
1209
|
-
return apply(function parent() {
|
|
1210
|
-
const child = this.subject;
|
|
1211
|
-
const expected = Expects.name;
|
|
1212
|
-
const value = Parent.get(this.subject);
|
|
1213
|
-
if (!value) {
|
|
1214
|
-
if (required)
|
|
1215
|
-
throw Oops$1.ParentRequired(expected, child);
|
|
1216
|
-
}
|
|
1217
|
-
else if (!(value instanceof Expects))
|
|
1218
|
-
throw Oops$1.UnexpectedParent(expected, child, value);
|
|
1219
|
-
return { value };
|
|
1220
|
-
});
|
|
1221
|
-
}
|
|
1222
|
-
|
|
1223
|
-
function on(initial, cb) {
|
|
1224
|
-
return apply(function on(key) {
|
|
1225
|
-
this.manage(key, initial, cb && createValueEffect(cb));
|
|
1226
|
-
});
|
|
1227
|
-
}
|
|
1228
|
-
function memo(factory, defer) {
|
|
1229
|
-
return apply(function memo(key) {
|
|
1230
|
-
const source = this.subject;
|
|
1231
|
-
const get = () => factory.call(source);
|
|
1232
|
-
if (defer)
|
|
1233
|
-
defineLazy(source, key, get);
|
|
1234
|
-
else
|
|
1235
|
-
define(source, key, get());
|
|
1236
|
-
});
|
|
1237
|
-
}
|
|
1238
|
-
function lazy(value) {
|
|
1239
|
-
return apply(function lazy(key) {
|
|
1240
|
-
const source = this.subject;
|
|
1241
|
-
source[key] = value;
|
|
1242
|
-
defineProperty(this.state, key, {
|
|
1243
|
-
get: () => source[key]
|
|
1244
|
-
});
|
|
1245
|
-
});
|
|
1246
1277
|
}
|
|
1247
1278
|
|
|
1248
1279
|
const Oops = issues({
|
|
@@ -1250,35 +1281,32 @@ const Oops = issues({
|
|
|
1250
1281
|
GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1251
1282
|
});
|
|
1252
1283
|
const Active = new WeakMap();
|
|
1253
|
-
class Singleton extends
|
|
1254
|
-
static get current() {
|
|
1255
|
-
return Active.get(this);
|
|
1256
|
-
}
|
|
1284
|
+
class Singleton extends MVC {
|
|
1257
1285
|
static create(...args) {
|
|
1258
1286
|
const Type = this;
|
|
1259
1287
|
if (Active.has(Type))
|
|
1260
1288
|
throw Oops.GlobalExists(this.name);
|
|
1261
|
-
|
|
1289
|
+
const instance = super.create(...args);
|
|
1262
1290
|
Active.set(Type, instance);
|
|
1263
1291
|
return instance;
|
|
1264
1292
|
}
|
|
1265
|
-
static
|
|
1266
|
-
const instance = this
|
|
1293
|
+
static set(updates) {
|
|
1294
|
+
const instance = Active.get(this) || this.create();
|
|
1267
1295
|
instance.import(updates);
|
|
1268
1296
|
return instance.update();
|
|
1269
1297
|
}
|
|
1270
|
-
static
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
static find(strict) {
|
|
1274
|
-
const instance = this.current;
|
|
1275
|
-
if (!instance && strict)
|
|
1298
|
+
static get(arg) {
|
|
1299
|
+
const instance = Active.get(this);
|
|
1300
|
+
if (!instance && arg !== false)
|
|
1276
1301
|
throw Oops.GlobalDoesNotExist(this.name);
|
|
1277
|
-
return
|
|
1302
|
+
return (typeof arg == "string" ?
|
|
1303
|
+
instance[arg] :
|
|
1304
|
+
instance);
|
|
1278
1305
|
}
|
|
1279
1306
|
static reset() {
|
|
1280
|
-
|
|
1281
|
-
|
|
1307
|
+
const current = Active.get(this);
|
|
1308
|
+
if (current)
|
|
1309
|
+
current.destroy();
|
|
1282
1310
|
}
|
|
1283
1311
|
destroy() {
|
|
1284
1312
|
super.destroy();
|
|
@@ -1286,5 +1314,5 @@ class Singleton extends Model {
|
|
|
1286
1314
|
}
|
|
1287
1315
|
}
|
|
1288
1316
|
|
|
1289
|
-
export { Consumer, Model, Provider, Singleton, act, apply, child,
|
|
1317
|
+
export { Consumer, MVC as Model, Provider, Singleton, act, apply, child, MVC as default, from, lazy, set as memo, on, parent, pending, ref, set, tap, use$1 as use };
|
|
1290
1318
|
//# sourceMappingURL=index.esm.js.map
|