@expressive/mvc 1.0.0-beta.33 → 1.0.0-beta.36
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 +841 -823
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +847 -825
- 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 +49 -62
- 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 = {};
|
|
@@ -23,7 +47,7 @@ function issues(register) {
|
|
|
23
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
|
}
|
|
@@ -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)
|
|
@@ -67,93 +91,185 @@ function createValueEffect(callback) {
|
|
|
67
91
|
else
|
|
68
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
|
+
setTimeout(() => {
|
|
172
|
+
UPDATE.delete(this.subject);
|
|
173
|
+
}, 0);
|
|
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.debug = () => {
|
|
98
|
-
const update = [];
|
|
99
|
-
this.notify = keys => {
|
|
100
|
-
update.splice(0, update.length, ...keys.filter(k => k in this.handle));
|
|
101
|
-
};
|
|
102
|
-
return update;
|
|
103
|
-
};
|
|
104
|
-
this.listen = (key, from) => {
|
|
105
|
-
const handler = this.handle[key];
|
|
106
|
-
if (!handler)
|
|
107
|
-
return;
|
|
108
|
-
if (typeof handler == "function")
|
|
109
|
-
handler();
|
|
110
|
-
const notify = this.onUpdate(key, from);
|
|
111
|
-
if (notify)
|
|
112
|
-
from.waiting.add(notify);
|
|
113
|
-
if (this.notify)
|
|
114
|
-
from.waiting.add(this.notify);
|
|
115
|
-
};
|
|
116
215
|
if (!(parent instanceof Controller))
|
|
117
|
-
parent =
|
|
216
|
+
parent = getController(parent);
|
|
118
217
|
this.parent = parent;
|
|
119
218
|
this.source = parent.subject;
|
|
120
|
-
this.proxy = create(parent.subject);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
for (const key in parent.state)
|
|
124
|
-
this.spy(key);
|
|
125
|
-
}
|
|
126
|
-
spy(key) {
|
|
127
|
-
const { proxy, source } = this;
|
|
128
|
-
const { set } = getOwnPropertyDescriptor(source, key);
|
|
129
|
-
const intercept = () => {
|
|
130
|
-
this.follow(key);
|
|
131
|
-
delete proxy[key];
|
|
132
|
-
return proxy[key];
|
|
219
|
+
const proxy = this.proxy = create(parent.subject);
|
|
220
|
+
const DEBUG = (keys) => {
|
|
221
|
+
UPDATE.set(proxy, keys.filter(k => k in this.watch));
|
|
133
222
|
};
|
|
134
|
-
|
|
135
|
-
defineProperty(
|
|
136
|
-
get:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
223
|
+
define(proxy, LOCAL, this);
|
|
224
|
+
defineProperty(this, "proxy", {
|
|
225
|
+
get: () => {
|
|
226
|
+
if (UPDATE.has(proxy))
|
|
227
|
+
setTimeout(() => {
|
|
228
|
+
UPDATE.delete(proxy);
|
|
229
|
+
}, 0);
|
|
230
|
+
return proxy;
|
|
231
|
+
}
|
|
140
232
|
});
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
|
246
|
+
});
|
|
247
|
+
}
|
|
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
|
+
};
|
|
152
268
|
};
|
|
153
269
|
}
|
|
154
270
|
}
|
|
155
271
|
|
|
156
|
-
const Oops$
|
|
272
|
+
const Oops$7 = issues({
|
|
157
273
|
ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
158
274
|
ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
159
275
|
});
|
|
@@ -179,7 +295,7 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
179
295
|
return setter.call(sub.proxy, sub.proxy);
|
|
180
296
|
}
|
|
181
297
|
catch (err) {
|
|
182
|
-
Oops$
|
|
298
|
+
Oops$7.ComputeFailed(subject, key, !!initial).warn();
|
|
183
299
|
throw err;
|
|
184
300
|
}
|
|
185
301
|
}
|
|
@@ -225,12 +341,12 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
225
341
|
}
|
|
226
342
|
catch (e) {
|
|
227
343
|
if (early)
|
|
228
|
-
Oops$
|
|
344
|
+
Oops$7.ComputedEarly(key).warn();
|
|
229
345
|
throw e;
|
|
230
346
|
}
|
|
231
347
|
finally {
|
|
232
348
|
sub.commit();
|
|
233
|
-
for (const key in sub.
|
|
349
|
+
for (const key in sub.watch) {
|
|
234
350
|
const peer = register.get(key);
|
|
235
351
|
if (peer && peer.priority >= info.priority)
|
|
236
352
|
info.priority = peer.priority + 1;
|
|
@@ -250,7 +366,7 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
250
366
|
enumerable: true
|
|
251
367
|
});
|
|
252
368
|
}
|
|
253
|
-
function ensure(on, keys) {
|
|
369
|
+
function ensure$1(on, keys) {
|
|
254
370
|
for (const key of keys) {
|
|
255
371
|
const desc = getOwnPropertyDescriptor(on.subject, key);
|
|
256
372
|
const getter = desc && desc.get;
|
|
@@ -273,6 +389,287 @@ function flush(on) {
|
|
|
273
389
|
KEYS.delete(on);
|
|
274
390
|
}
|
|
275
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
|
+
|
|
276
673
|
const Lifecycle = {
|
|
277
674
|
WILL_RENDER: "willRender",
|
|
278
675
|
WILL_UPDATE: "willUpdate",
|
|
@@ -280,7 +677,7 @@ const Lifecycle = {
|
|
|
280
677
|
WILL_UNMOUNT: "willUnmount",
|
|
281
678
|
DID_MOUNT: "didMount"
|
|
282
679
|
};
|
|
283
|
-
|
|
680
|
+
[
|
|
284
681
|
"didCreate",
|
|
285
682
|
"willDestroy",
|
|
286
683
|
...values(Lifecycle)
|
|
@@ -288,7 +685,7 @@ const lifecycleEvents = [
|
|
|
288
685
|
function lifecycle(prefix) {
|
|
289
686
|
const type = eventsFor(prefix);
|
|
290
687
|
return function useLifecycle(sub, tag) {
|
|
291
|
-
const emit = useMemo(() => {
|
|
688
|
+
const emit = React.useMemo(() => {
|
|
292
689
|
const subject = sub.source;
|
|
293
690
|
const id = typeof tag == "function" ? tag(subject) : tag;
|
|
294
691
|
return (name) => {
|
|
@@ -300,7 +697,7 @@ function lifecycle(prefix) {
|
|
|
300
697
|
emit(sub.active
|
|
301
698
|
? Lifecycle.WILL_UPDATE
|
|
302
699
|
: Lifecycle.WILL_MOUNT);
|
|
303
|
-
useLayoutEffect(() => {
|
|
700
|
+
React.useLayoutEffect(() => {
|
|
304
701
|
sub.commit();
|
|
305
702
|
emit(Lifecycle.DID_MOUNT);
|
|
306
703
|
return () => {
|
|
@@ -314,254 +711,264 @@ function eventsFor(prefix) {
|
|
|
314
711
|
const map = new Map();
|
|
315
712
|
for (const name of values(Lifecycle)) {
|
|
316
713
|
const alias = prefix + name[0].toUpperCase() + name.slice(1);
|
|
317
|
-
lifecycleEvents.push(alias);
|
|
318
714
|
map.set(name, alias);
|
|
319
715
|
}
|
|
320
716
|
return (e) => map.get(e);
|
|
321
717
|
}
|
|
322
718
|
|
|
323
|
-
const
|
|
324
|
-
const
|
|
325
|
-
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
|
|
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];
|
|
329
726
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
if (typeof output == "function") {
|
|
337
|
-
const getter = output;
|
|
338
|
-
output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
|
|
339
|
-
return getter(this[LOCAL]);
|
|
340
|
-
} });
|
|
341
|
-
}
|
|
342
|
-
if (output)
|
|
343
|
-
defineProperty(this.subject, key, output);
|
|
344
|
-
}
|
|
345
|
-
Pending.set(placeholder, setup);
|
|
346
|
-
return placeholder;
|
|
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;
|
|
347
733
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
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
|
-
|
|
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;
|
|
381
770
|
}
|
|
382
|
-
|
|
383
|
-
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
return sub;
|
|
774
|
+
});
|
|
775
|
+
React.useLayoutEffect(() => hook.commit(), []);
|
|
776
|
+
return hook.proxy;
|
|
777
|
+
}
|
|
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;
|
|
384
790
|
}
|
|
791
|
+
else
|
|
792
|
+
refresh();
|
|
793
|
+
};
|
|
794
|
+
if (value instanceof Promise) {
|
|
795
|
+
value.then(set);
|
|
796
|
+
value = undefined;
|
|
385
797
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
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;
|
|
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
|
+
};
|
|
403
829
|
});
|
|
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();
|
|
404
842
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
return;
|
|
410
|
-
if (handler)
|
|
411
|
-
switch (handler.call(subject, value)) {
|
|
412
|
-
case true:
|
|
413
|
-
this.update(key);
|
|
414
|
-
case false:
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
this.update(key, value);
|
|
418
|
-
};
|
|
419
|
-
}
|
|
420
|
-
addListener(listener) {
|
|
421
|
-
this.followers.add(listener);
|
|
422
|
-
return () => {
|
|
423
|
-
this.followers.delete(listener);
|
|
424
|
-
};
|
|
843
|
+
get local() {
|
|
844
|
+
return [
|
|
845
|
+
...new Set(getOwnPropertySymbols(this).map(symbol => this[symbol]))
|
|
846
|
+
];
|
|
425
847
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
if (!this.frame.size)
|
|
432
|
-
setTimeout(() => this.emit(), 0);
|
|
433
|
-
this.frame.add(key);
|
|
434
|
-
for (const subscription of this.followers) {
|
|
435
|
-
const notify = subscription(key, this);
|
|
436
|
-
if (notify)
|
|
437
|
-
this.waiting.add(notify);
|
|
848
|
+
key(T) {
|
|
849
|
+
let key = this.table.get(T);
|
|
850
|
+
if (!key) {
|
|
851
|
+
key = Symbol(T.name);
|
|
852
|
+
this.table.set(T, key);
|
|
438
853
|
}
|
|
854
|
+
return key;
|
|
439
855
|
}
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
const keys = Object.freeze([...this.frame]);
|
|
443
|
-
const handle = new Set(this.waiting);
|
|
444
|
-
this.waiting.clear();
|
|
445
|
-
this.frame.clear();
|
|
446
|
-
defineProperty(this.subject, UPDATE, {
|
|
447
|
-
configurable: true,
|
|
448
|
-
value: keys
|
|
449
|
-
});
|
|
450
|
-
handle.forEach(callback => {
|
|
451
|
-
try {
|
|
452
|
-
callback(keys);
|
|
453
|
-
}
|
|
454
|
-
catch (e) { }
|
|
455
|
-
});
|
|
856
|
+
get(T) {
|
|
857
|
+
return this[this.key(T)];
|
|
456
858
|
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
if (typeof using == "object") {
|
|
462
|
-
using = Array.from(using);
|
|
463
|
-
if (using.length === 0)
|
|
464
|
-
using = undefined;
|
|
859
|
+
push(I) {
|
|
860
|
+
const next = create(this);
|
|
861
|
+
if (I instanceof Model || typeof I == "function")
|
|
862
|
+
next.register(I);
|
|
465
863
|
else
|
|
466
|
-
|
|
864
|
+
for (const i of values(I))
|
|
865
|
+
next.register(i);
|
|
866
|
+
return next;
|
|
467
867
|
}
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
const current = source.call(this, key);
|
|
475
|
-
function subscribe(sub) {
|
|
476
|
-
let child;
|
|
477
|
-
function start() {
|
|
478
|
-
const instance = current();
|
|
479
|
-
if (instance) {
|
|
480
|
-
child = new Subscriber(instance, sub.onUpdate);
|
|
481
|
-
if (sub.active)
|
|
482
|
-
child.commit();
|
|
483
|
-
sub.dependant.add(child);
|
|
484
|
-
context.set(sub, child.proxy);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
function restart() {
|
|
488
|
-
if (child) {
|
|
489
|
-
child.release();
|
|
490
|
-
sub.dependant.delete(child);
|
|
491
|
-
context.set(sub, undefined);
|
|
492
|
-
child = undefined;
|
|
493
|
-
}
|
|
494
|
-
start();
|
|
495
|
-
}
|
|
496
|
-
start();
|
|
497
|
-
sub.follow(key, restart);
|
|
868
|
+
register(I) {
|
|
869
|
+
let writable = true;
|
|
870
|
+
let T;
|
|
871
|
+
if (I instanceof Model) {
|
|
872
|
+
T = I.constructor;
|
|
873
|
+
writable = false;
|
|
498
874
|
}
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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;
|
|
890
|
+
}
|
|
891
|
+
pop() {
|
|
892
|
+
for (const key of getOwnPropertySymbols(this)) {
|
|
893
|
+
const entry = getOwnPropertyDescriptor(this, key);
|
|
894
|
+
if (entry.writable)
|
|
895
|
+
entry.value.destroy();
|
|
896
|
+
}
|
|
897
|
+
}
|
|
507
898
|
}
|
|
508
899
|
|
|
509
|
-
const Oops$
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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.`
|
|
513
904
|
});
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
});
|
|
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;
|
|
522
912
|
}
|
|
523
|
-
function
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
get: onGet
|
|
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;
|
|
557
946
|
};
|
|
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 {};
|
|
558
956
|
});
|
|
957
|
+
if (hook.commit)
|
|
958
|
+
React.useLayoutEffect(() => hook.commit(), []);
|
|
959
|
+
return props.render(hook.proxy);
|
|
559
960
|
}
|
|
560
|
-
function
|
|
561
|
-
|
|
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);
|
|
562
969
|
}
|
|
563
970
|
|
|
564
|
-
const Oops$
|
|
971
|
+
const Oops$4 = issues({
|
|
565
972
|
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
566
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.`
|
|
567
974
|
});
|
|
@@ -569,14 +976,16 @@ const PendingContext = new WeakMap();
|
|
|
569
976
|
const ContextWasUsed = new WeakMap();
|
|
570
977
|
function tap(type, argument) {
|
|
571
978
|
return child(function tap(key) {
|
|
572
|
-
return
|
|
979
|
+
return {
|
|
980
|
+
get: pendingAccess(this.subject, type, key, argument)
|
|
981
|
+
};
|
|
573
982
|
});
|
|
574
983
|
}
|
|
575
984
|
function pendingAccess(from, type, key, argument) {
|
|
576
|
-
if ("
|
|
577
|
-
return () => type.
|
|
578
|
-
if ("
|
|
579
|
-
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);
|
|
580
989
|
let instance;
|
|
581
990
|
getPending(from).push(context => {
|
|
582
991
|
instance = context.get(type);
|
|
@@ -585,7 +994,7 @@ function pendingAccess(from, type, key, argument) {
|
|
|
585
994
|
instance = undefined;
|
|
586
995
|
}
|
|
587
996
|
else if (!instance && argument)
|
|
588
|
-
throw Oops$
|
|
997
|
+
throw Oops$4.AmbientRequired(type.name, from, key);
|
|
589
998
|
});
|
|
590
999
|
return () => instance;
|
|
591
1000
|
}
|
|
@@ -611,7 +1020,7 @@ function getPending(subject) {
|
|
|
611
1020
|
return pending;
|
|
612
1021
|
}
|
|
613
1022
|
|
|
614
|
-
const Oops$
|
|
1023
|
+
const Oops$3 = issues({
|
|
615
1024
|
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
|
|
616
1025
|
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
617
1026
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
@@ -628,7 +1037,7 @@ function ref(arg) {
|
|
|
628
1037
|
return apply(function ref(key) {
|
|
629
1038
|
let value = {};
|
|
630
1039
|
if (typeof arg == "object") {
|
|
631
|
-
const source =
|
|
1040
|
+
const source = getController(arg);
|
|
632
1041
|
for (const key in source.state)
|
|
633
1042
|
defineLazy(value, key, createRef.bind(source, key));
|
|
634
1043
|
}
|
|
@@ -642,7 +1051,7 @@ function act(task) {
|
|
|
642
1051
|
let pending = false;
|
|
643
1052
|
const invoke = (...args) => {
|
|
644
1053
|
if (pending)
|
|
645
|
-
return Promise.reject(Oops$
|
|
1054
|
+
return Promise.reject(Oops$3.DuplicateAction(key));
|
|
646
1055
|
pending = true;
|
|
647
1056
|
this.update(key);
|
|
648
1057
|
return new Promise(res => {
|
|
@@ -665,17 +1074,17 @@ function act(task) {
|
|
|
665
1074
|
}
|
|
666
1075
|
function from(source, setter, argument) {
|
|
667
1076
|
return apply(function from(key) {
|
|
668
|
-
const { subject } = this;
|
|
669
1077
|
let getSource;
|
|
670
|
-
|
|
1078
|
+
const { subject } = this;
|
|
1079
|
+
const getter = argument === true
|
|
671
1080
|
? pendingValue
|
|
672
1081
|
: argument || undefined;
|
|
673
1082
|
// Easy mistake, using a peer, will always be unresolved.
|
|
674
1083
|
if (typeof source == "symbol")
|
|
675
|
-
throw Oops$
|
|
1084
|
+
throw Oops$3.PeerNotAllowed(subject, key);
|
|
676
1085
|
// replace source controller in-case different
|
|
677
1086
|
if (typeof source == "object")
|
|
678
|
-
getSource = () =>
|
|
1087
|
+
getSource = () => getController(source);
|
|
679
1088
|
// specifically an arrow function (getter factory)
|
|
680
1089
|
else if (!source.prototype) {
|
|
681
1090
|
setter = source.call(subject, key);
|
|
@@ -686,12 +1095,12 @@ function from(source, setter, argument) {
|
|
|
686
1095
|
getSource = pendingAccess(subject, source, key, true);
|
|
687
1096
|
// Regular function is too ambiguous so not allowed.
|
|
688
1097
|
else
|
|
689
|
-
throw Oops$
|
|
1098
|
+
throw Oops$3.BadComputedSource(subject, key, source);
|
|
690
1099
|
prepare(this, key, getSource, setter, getter);
|
|
691
1100
|
});
|
|
692
1101
|
}
|
|
693
1102
|
|
|
694
|
-
const Oops$
|
|
1103
|
+
const Oops$2 = issues({
|
|
695
1104
|
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
696
1105
|
});
|
|
697
1106
|
/* deprecated - ignore coverage */
|
|
@@ -725,423 +1134,130 @@ function pendingFactory(via, key, fn) {
|
|
|
725
1134
|
if (error)
|
|
726
1135
|
throw error;
|
|
727
1136
|
if (key in state)
|
|
728
|
-
return state[key];
|
|
729
|
-
let output;
|
|
730
|
-
try {
|
|
731
|
-
output = fn.call(subject, key, subject);
|
|
732
|
-
}
|
|
733
|
-
catch (err) {
|
|
734
|
-
throw error = err;
|
|
735
|
-
}
|
|
736
|
-
if (output instanceof Promise) {
|
|
737
|
-
const issue = Oops$4.ValueNotReady(subject, key);
|
|
738
|
-
output
|
|
739
|
-
.catch(err => error = err)
|
|
740
|
-
.then(out => state[key] = out)
|
|
741
|
-
.finally(() => waiting = undefined);
|
|
742
|
-
throw waiting = Object.assign(output, {
|
|
743
|
-
message: issue.message,
|
|
744
|
-
stack: issue.stack
|
|
745
|
-
});
|
|
746
|
-
}
|
|
747
|
-
else {
|
|
748
|
-
return state[key] = output;
|
|
749
|
-
}
|
|
750
|
-
};
|
|
751
|
-
}
|
|
752
|
-
function suspend(source, key) {
|
|
753
|
-
const error = Oops$4.ValueNotReady(source.subject, key);
|
|
754
|
-
const promise = new Promise(resolve => {
|
|
755
|
-
const release = source.addListener(forKey => {
|
|
756
|
-
if (forKey == key)
|
|
757
|
-
return () => {
|
|
758
|
-
if (source.state[key] !== undefined) {
|
|
759
|
-
release();
|
|
760
|
-
resolve();
|
|
761
|
-
}
|
|
762
|
-
};
|
|
763
|
-
});
|
|
764
|
-
});
|
|
765
|
-
return Object.assign(promise, {
|
|
766
|
-
toString: () => String(error),
|
|
767
|
-
name: "Suspense",
|
|
768
|
-
message: error.message,
|
|
769
|
-
stack: error.stack
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
function use$1(init) {
|
|
774
|
-
const [state, update] = useState(() => [
|
|
775
|
-
init(() => update(state.concat()))
|
|
776
|
-
]);
|
|
777
|
-
return state[0];
|
|
778
|
-
}
|
|
779
|
-
function useLazy(Type, callback) {
|
|
780
|
-
const instance = useMemo(() => {
|
|
781
|
-
const instance = Type.create();
|
|
782
|
-
if (callback)
|
|
783
|
-
callback(instance);
|
|
784
|
-
return instance;
|
|
785
|
-
}, []);
|
|
786
|
-
useLayoutEffect(() => () => instance.destroy(), []);
|
|
787
|
-
return instance;
|
|
788
|
-
}
|
|
789
|
-
function useWatcher(target, focus, expected) {
|
|
790
|
-
const hook = use$1(refresh => {
|
|
791
|
-
const sub = new Subscriber(target, () => refresh);
|
|
792
|
-
if (focus) {
|
|
793
|
-
const source = sub.proxy;
|
|
794
|
-
defineProperty(sub, "proxy", {
|
|
795
|
-
get() {
|
|
796
|
-
const value = source[focus];
|
|
797
|
-
if (value === undefined && expected)
|
|
798
|
-
throw suspend(sub.parent, focus);
|
|
799
|
-
return value;
|
|
800
|
-
}
|
|
801
|
-
});
|
|
802
|
-
}
|
|
803
|
-
return sub;
|
|
804
|
-
});
|
|
805
|
-
useLayoutEffect(() => hook.commit(), []);
|
|
806
|
-
return hook.proxy;
|
|
807
|
-
}
|
|
808
|
-
function useComputed(target, compute, expected) {
|
|
809
|
-
const hook = use$1(refresh => {
|
|
810
|
-
const sub = new Subscriber(target, () => update);
|
|
811
|
-
const { proxy } = sub;
|
|
812
|
-
let value;
|
|
813
|
-
let retry;
|
|
814
|
-
const update = () => {
|
|
815
|
-
const next = compute.call(proxy, proxy);
|
|
816
|
-
if (value == next)
|
|
817
|
-
return;
|
|
818
|
-
value = next;
|
|
819
|
-
if (retry) {
|
|
820
|
-
retry();
|
|
821
|
-
retry = undefined;
|
|
822
|
-
}
|
|
823
|
-
else
|
|
824
|
-
refresh();
|
|
825
|
-
};
|
|
826
|
-
const access = () => {
|
|
827
|
-
if (value === undefined && expected)
|
|
828
|
-
throw new Promise(res => {
|
|
829
|
-
retry = res;
|
|
830
|
-
});
|
|
831
|
-
return value;
|
|
832
|
-
};
|
|
833
|
-
value = compute.call(proxy, proxy);
|
|
834
|
-
sub.commit();
|
|
835
|
-
defineProperty(sub, "proxy", { get: access });
|
|
836
|
-
return sub;
|
|
837
|
-
});
|
|
838
|
-
useLayoutEffect(() => hook.release, []);
|
|
839
|
-
return hook.proxy;
|
|
840
|
-
}
|
|
841
|
-
function useModel(Type, callback) {
|
|
842
|
-
const hook = use$1(refresh => {
|
|
843
|
-
const instance = new Type();
|
|
844
|
-
const control = manage(instance);
|
|
845
|
-
const sub = new Subscriber(control, () => refresh);
|
|
846
|
-
const release = control.addListener((key) => {
|
|
847
|
-
if (key == Lifecycle.WILL_UNMOUNT)
|
|
848
|
-
return () => {
|
|
849
|
-
instance.destroy();
|
|
850
|
-
release();
|
|
851
|
-
};
|
|
852
|
-
});
|
|
853
|
-
if (callback)
|
|
854
|
-
callback(instance);
|
|
855
|
-
return sub;
|
|
856
|
-
});
|
|
857
|
-
return hook.proxy;
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
class Lookup {
|
|
861
|
-
constructor() {
|
|
862
|
-
this.table = new Map();
|
|
863
|
-
}
|
|
864
|
-
get local() {
|
|
865
|
-
return getOwnPropertySymbols(this).map((symbol) => this[symbol]);
|
|
866
|
-
}
|
|
867
|
-
key(T) {
|
|
868
|
-
let key = this.table.get(T);
|
|
869
|
-
if (!key) {
|
|
870
|
-
key = Symbol(T.name);
|
|
871
|
-
this.table.set(T, key);
|
|
872
|
-
}
|
|
873
|
-
return key;
|
|
874
|
-
}
|
|
875
|
-
get(T) {
|
|
876
|
-
return this[this.key(T)];
|
|
877
|
-
}
|
|
878
|
-
push(I) {
|
|
879
|
-
const next = create(this);
|
|
880
|
-
if (I instanceof Model || typeof I == "function")
|
|
881
|
-
next.register(I);
|
|
882
|
-
else
|
|
883
|
-
for (const i of values(I))
|
|
884
|
-
next.register(i);
|
|
885
|
-
return next;
|
|
886
|
-
}
|
|
887
|
-
register(I) {
|
|
888
|
-
let writable = true;
|
|
889
|
-
let T;
|
|
890
|
-
if (I instanceof Model) {
|
|
891
|
-
T = I.constructor;
|
|
892
|
-
writable = false;
|
|
1137
|
+
return state[key];
|
|
1138
|
+
let output;
|
|
1139
|
+
try {
|
|
1140
|
+
output = fn.call(subject, key, subject);
|
|
893
1141
|
}
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
I = I.create();
|
|
1142
|
+
catch (err) {
|
|
1143
|
+
throw error = err;
|
|
897
1144
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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
|
|
901
1154
|
});
|
|
902
|
-
T = getPrototypeOf(T);
|
|
903
|
-
} while (T !== Model);
|
|
904
|
-
return I;
|
|
905
|
-
}
|
|
906
|
-
pop() {
|
|
907
|
-
for (const key of getOwnPropertySymbols(this)) {
|
|
908
|
-
const entry = getOwnPropertyDescriptor(this, key);
|
|
909
|
-
if (entry.writable)
|
|
910
|
-
entry.value.destroy();
|
|
911
1155
|
}
|
|
912
|
-
|
|
1156
|
+
else {
|
|
1157
|
+
return state[key] = output;
|
|
1158
|
+
}
|
|
1159
|
+
};
|
|
1160
|
+
}
|
|
1161
|
+
function suspend(source, key) {
|
|
1162
|
+
const error = Oops$2.ValueNotReady(source.subject, key);
|
|
1163
|
+
const promise = new Promise(resolve => {
|
|
1164
|
+
const release = source.addListener(forKey => {
|
|
1165
|
+
if (forKey == key)
|
|
1166
|
+
return () => {
|
|
1167
|
+
if (source.state[key] !== undefined) {
|
|
1168
|
+
release();
|
|
1169
|
+
resolve();
|
|
1170
|
+
}
|
|
1171
|
+
};
|
|
1172
|
+
});
|
|
1173
|
+
});
|
|
1174
|
+
return Object.assign(promise, {
|
|
1175
|
+
toString: () => String(error),
|
|
1176
|
+
name: "Suspense",
|
|
1177
|
+
message: error.message,
|
|
1178
|
+
stack: error.stack
|
|
1179
|
+
});
|
|
913
1180
|
}
|
|
914
1181
|
|
|
915
|
-
const Oops$
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
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.`
|
|
919
1186
|
});
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
}
|
|
928
|
-
function Consumer(props) {
|
|
929
|
-
const { get, has, children, of: Control } = props;
|
|
930
|
-
if (typeof children == "function")
|
|
931
|
-
return children(Control.tap());
|
|
932
|
-
const callback = has || get;
|
|
933
|
-
if (typeof callback == "function")
|
|
934
|
-
callback(Control.get(!!has));
|
|
935
|
-
else
|
|
936
|
-
throw Oops$3.BadConsumerProps();
|
|
937
|
-
return null;
|
|
938
|
-
}
|
|
939
|
-
function useNewContext(from, inject) {
|
|
940
|
-
return useMemo(() => {
|
|
941
|
-
if (!inject)
|
|
942
|
-
throw Oops$3.NoProviderType();
|
|
943
|
-
const context = from.push(inject);
|
|
944
|
-
for (const instance of context.local)
|
|
945
|
-
for (const apply of getPending(instance))
|
|
946
|
-
apply(context);
|
|
947
|
-
return context;
|
|
948
|
-
}, []);
|
|
949
|
-
}
|
|
950
|
-
function useAppliedProps(within, props) {
|
|
951
|
-
const update = useMemo(() => {
|
|
952
|
-
const targets = within.local;
|
|
953
|
-
return function integrate(props) {
|
|
954
|
-
for (const [key, value] of entries(props))
|
|
955
|
-
if (key != "of" && key != "children")
|
|
956
|
-
for (const into of targets)
|
|
957
|
-
if (key in into)
|
|
958
|
-
into[key] = value;
|
|
959
|
-
};
|
|
960
|
-
}, []);
|
|
961
|
-
update(props);
|
|
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]
|
|
1193
|
+
});
|
|
1194
|
+
});
|
|
962
1195
|
}
|
|
963
|
-
function
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
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();
|
|
1205
|
+
else {
|
|
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
|
+
}
|
|
1219
|
+
}
|
|
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 };
|
|
969
1228
|
});
|
|
970
|
-
if (hook.commit)
|
|
971
|
-
useLayoutEffect(() => hook.commit(), []);
|
|
972
|
-
return props.render(hook.proxy);
|
|
973
1229
|
}
|
|
974
|
-
function
|
|
975
|
-
|
|
976
|
-
const current = useLookup();
|
|
977
|
-
const context = useNewContext(current, props.of);
|
|
978
|
-
useAppliedProps(context, props);
|
|
979
|
-
useLayoutEffect(() => () => context.pop(), []);
|
|
980
|
-
return createElement(LookupContext.Provider, { value: context }, typeof render == "function"
|
|
981
|
-
? createElement(RenderFunction, { context, render })
|
|
982
|
-
: render);
|
|
1230
|
+
function on(initial, onUpdate) {
|
|
1231
|
+
return set(initial && (() => initial), onUpdate);
|
|
983
1232
|
}
|
|
984
1233
|
|
|
985
|
-
|
|
986
|
-
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
987
|
-
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
988
|
-
});
|
|
989
|
-
const useElementLifecycle = lifecycle("element");
|
|
990
|
-
const useComponentLifecycle = lifecycle("component");
|
|
991
|
-
class Model {
|
|
992
|
-
constructor() {
|
|
993
|
-
const control = Controller.setup(this);
|
|
994
|
-
define(this, "get", this);
|
|
995
|
-
define(this, "set", this);
|
|
996
|
-
defer(control, "on");
|
|
997
|
-
defer(control, "effect");
|
|
998
|
-
control.waiting.add(() => {
|
|
999
|
-
delete this.on;
|
|
1000
|
-
delete this.effect;
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
1234
|
+
class MVC extends Model {
|
|
1003
1235
|
tap(path, expect) {
|
|
1004
|
-
|
|
1005
|
-
return useComputed(this, path, expect);
|
|
1006
|
-
const proxy = useWatcher(this, path, expect);
|
|
1007
|
-
this.update("willRender", true);
|
|
1008
|
-
return proxy;
|
|
1236
|
+
return useTap(this, path, expect);
|
|
1009
1237
|
}
|
|
1010
1238
|
tag(id) {
|
|
1011
|
-
|
|
1012
|
-
useElementLifecycle(hook, id || 0);
|
|
1013
|
-
return hook.proxy;
|
|
1239
|
+
return useTag(this, id);
|
|
1014
1240
|
}
|
|
1015
1241
|
use(callback) {
|
|
1016
|
-
|
|
1017
|
-
if (callback)
|
|
1018
|
-
callback(this);
|
|
1019
|
-
return new Subscriber(this, () => refresh);
|
|
1020
|
-
});
|
|
1021
|
-
useComponentLifecycle(hook);
|
|
1022
|
-
return hook.proxy;
|
|
1023
|
-
}
|
|
1024
|
-
on(subset, handler, squash, once) {
|
|
1025
|
-
const control = manage(this);
|
|
1026
|
-
const request = keys(control, subset);
|
|
1027
|
-
const callback = squash
|
|
1028
|
-
? handler.bind(this)
|
|
1029
|
-
: frame => frame
|
|
1030
|
-
.filter(k => request.includes(k))
|
|
1031
|
-
.forEach(k => handler.call(this, control.state[k], k));
|
|
1032
|
-
const trigger = once
|
|
1033
|
-
? frame => { remove(); callback(frame); }
|
|
1034
|
-
: callback;
|
|
1035
|
-
ensure(control, request);
|
|
1036
|
-
const remove = control.addListener(key => {
|
|
1037
|
-
if (request.includes(key))
|
|
1038
|
-
return trigger;
|
|
1039
|
-
});
|
|
1040
|
-
return remove;
|
|
1041
|
-
}
|
|
1042
|
-
once(select, callback, squash) {
|
|
1043
|
-
if (callback)
|
|
1044
|
-
return this.on(select, callback, squash, true);
|
|
1045
|
-
else
|
|
1046
|
-
return new Promise(resolve => {
|
|
1047
|
-
this.on(select, resolve, true, true);
|
|
1048
|
-
});
|
|
1049
|
-
}
|
|
1050
|
-
effect(callback, select) {
|
|
1051
|
-
const control = manage(this);
|
|
1052
|
-
let target = this;
|
|
1053
|
-
const effect = createEffect(callback);
|
|
1054
|
-
const invoke = () => effect.call(target, target);
|
|
1055
|
-
if (select) {
|
|
1056
|
-
invoke();
|
|
1057
|
-
return this.on(select, invoke, true);
|
|
1058
|
-
}
|
|
1059
|
-
const sub = new Subscriber(control, () => invoke);
|
|
1060
|
-
target = sub.proxy;
|
|
1061
|
-
invoke();
|
|
1062
|
-
return sub.commit();
|
|
1063
|
-
}
|
|
1064
|
-
import(from, subset) {
|
|
1065
|
-
for (const key of keys(manage(this), subset))
|
|
1066
|
-
if (key in from)
|
|
1067
|
-
this[key] = from[key];
|
|
1068
|
-
}
|
|
1069
|
-
export(subset) {
|
|
1070
|
-
const control = manage(this);
|
|
1071
|
-
const output = {};
|
|
1072
|
-
for (const key of keys(control, subset))
|
|
1073
|
-
output[key] = control.state[key];
|
|
1074
|
-
return output;
|
|
1075
|
-
}
|
|
1076
|
-
update(arg, tag) {
|
|
1077
|
-
const control = manage(this);
|
|
1078
|
-
if (typeof arg == "function")
|
|
1079
|
-
arg = select(this, arg);
|
|
1080
|
-
if (typeof arg == "boolean") {
|
|
1081
|
-
if (!control.pending === arg)
|
|
1082
|
-
return Promise.reject(Oops$2.StrictUpdate(arg));
|
|
1083
|
-
}
|
|
1084
|
-
else if (arg) {
|
|
1085
|
-
control.update(arg);
|
|
1086
|
-
if (1 in arguments && arg in this) {
|
|
1087
|
-
const method = this[arg];
|
|
1088
|
-
if (typeof method == "function")
|
|
1089
|
-
if (typeof tag != "boolean")
|
|
1090
|
-
method.call(this, tag);
|
|
1091
|
-
else if (tag)
|
|
1092
|
-
method.call(this);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
return {
|
|
1096
|
-
then(callback) {
|
|
1097
|
-
if (callback)
|
|
1098
|
-
if (control.pending)
|
|
1099
|
-
control.waiting.add(callback);
|
|
1100
|
-
else
|
|
1101
|
-
callback(false);
|
|
1102
|
-
else
|
|
1103
|
-
throw Oops$2.NoChaining();
|
|
1104
|
-
}
|
|
1105
|
-
};
|
|
1106
|
-
}
|
|
1107
|
-
destroy() {
|
|
1108
|
-
this.update("willDestroy", true);
|
|
1109
|
-
}
|
|
1110
|
-
toString() {
|
|
1111
|
-
return this.constructor.name;
|
|
1112
|
-
}
|
|
1113
|
-
static create(...args) {
|
|
1114
|
-
const instance = new this(...args);
|
|
1115
|
-
manage(instance);
|
|
1116
|
-
return instance;
|
|
1242
|
+
return useNew(this, callback);
|
|
1117
1243
|
}
|
|
1118
1244
|
static new(callback) {
|
|
1119
|
-
|
|
1120
|
-
instance.update("willRender", true);
|
|
1121
|
-
return instance;
|
|
1122
|
-
}
|
|
1123
|
-
static find(strict) {
|
|
1124
|
-
return useFromContext(this, strict);
|
|
1245
|
+
return usePassive(this, callback);
|
|
1125
1246
|
}
|
|
1126
1247
|
static get(key) {
|
|
1127
|
-
const instance = this
|
|
1128
|
-
return (typeof key == "
|
|
1129
|
-
key
|
|
1130
|
-
|
|
1131
|
-
instance[key] :
|
|
1132
|
-
instance);
|
|
1248
|
+
const instance = useContext(this, key !== false);
|
|
1249
|
+
return (typeof key == "string" ?
|
|
1250
|
+
instance[key] :
|
|
1251
|
+
instance);
|
|
1133
1252
|
}
|
|
1134
1253
|
static tap(key, expect) {
|
|
1135
|
-
return this.
|
|
1254
|
+
return this.get().tap(key, expect);
|
|
1136
1255
|
}
|
|
1137
1256
|
static tag(id) {
|
|
1138
|
-
return this.
|
|
1257
|
+
return this.get().tag(id);
|
|
1139
1258
|
}
|
|
1140
1259
|
static use(callback) {
|
|
1141
|
-
|
|
1142
|
-
useComponentLifecycle(instance[LOCAL]);
|
|
1143
|
-
usePeerContext(instance.get);
|
|
1144
|
-
return instance;
|
|
1260
|
+
return useModel(this, callback);
|
|
1145
1261
|
}
|
|
1146
1262
|
static uses(props, only) {
|
|
1147
1263
|
return this.use(instance => {
|
|
@@ -1153,106 +1269,11 @@ class Model {
|
|
|
1153
1269
|
instance.import(props, only);
|
|
1154
1270
|
return instance;
|
|
1155
1271
|
}
|
|
1156
|
-
static meta(path) {
|
|
1272
|
+
static meta(path, expect) {
|
|
1157
1273
|
return typeof path == "function"
|
|
1158
|
-
? useComputed(this, path)
|
|
1159
|
-
:
|
|
1160
|
-
}
|
|
1161
|
-
static isTypeof(maybe) {
|
|
1162
|
-
return (typeof maybe == "function" &&
|
|
1163
|
-
maybe.prototype instanceof this);
|
|
1274
|
+
? useComputed(this, path, expect)
|
|
1275
|
+
: useActive(this, path, expect);
|
|
1164
1276
|
}
|
|
1165
|
-
}
|
|
1166
|
-
Model.CONTROL = CONTROL;
|
|
1167
|
-
Model.STATE = STATE;
|
|
1168
|
-
Model.LOCAL = LOCAL;
|
|
1169
|
-
Model.WHY = UPDATE;
|
|
1170
|
-
defineLazy(Model, CONTROL, function () {
|
|
1171
|
-
return new Controller(this).start();
|
|
1172
|
-
});
|
|
1173
|
-
function defer(on, method) {
|
|
1174
|
-
const { subject, waiting } = on;
|
|
1175
|
-
const real = subject[method];
|
|
1176
|
-
subject[method] = (...args) => {
|
|
1177
|
-
let done;
|
|
1178
|
-
waiting.add(() => {
|
|
1179
|
-
done = real.apply(subject, args);
|
|
1180
|
-
});
|
|
1181
|
-
return () => done();
|
|
1182
|
-
};
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
const Parent = new WeakMap();
|
|
1186
|
-
const Oops$1 = issues({
|
|
1187
|
-
ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
1188
|
-
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
1189
|
-
UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
|
|
1190
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1191
|
-
IsReadOnly: (owner, key) => `${owner}.${key} is set to read-only, but tried to reassign assign.`,
|
|
1192
|
-
MustBeDefined: (owner, key) => `${owner}.${key} must have initial value, as a read-only property.`
|
|
1193
|
-
});
|
|
1194
|
-
function bootstrap(object) {
|
|
1195
|
-
const breakdown = getOwnPropertyDescriptors(object);
|
|
1196
|
-
const control = new Model();
|
|
1197
|
-
for (const key in breakdown)
|
|
1198
|
-
defineProperty(control, key, breakdown[key]);
|
|
1199
|
-
return control;
|
|
1200
|
-
}
|
|
1201
|
-
function use(input, argument) {
|
|
1202
|
-
return child(function use(key) {
|
|
1203
|
-
const { subject } = this;
|
|
1204
|
-
// `true` => readonly
|
|
1205
|
-
// `false` => writable, may be undefined
|
|
1206
|
-
// `undefined` => writable (default)
|
|
1207
|
-
let mode = argument;
|
|
1208
|
-
let current;
|
|
1209
|
-
const onUpdate = (next, initial) => {
|
|
1210
|
-
if (mode === true && !initial)
|
|
1211
|
-
throw Oops$1.IsReadOnly(subject, key);
|
|
1212
|
-
if (next) {
|
|
1213
|
-
current = next instanceof Model
|
|
1214
|
-
? next : bootstrap(next);
|
|
1215
|
-
Parent.set(current, subject);
|
|
1216
|
-
manage(current);
|
|
1217
|
-
}
|
|
1218
|
-
else if (mode === undefined)
|
|
1219
|
-
throw Oops$1.UndefinedNotAllowed(key);
|
|
1220
|
-
else
|
|
1221
|
-
current = undefined;
|
|
1222
|
-
if (typeof argument == "function")
|
|
1223
|
-
return argument(current);
|
|
1224
|
-
};
|
|
1225
|
-
if (input) {
|
|
1226
|
-
current =
|
|
1227
|
-
Model.isTypeof(input) ? new input() :
|
|
1228
|
-
input instanceof Model ? input :
|
|
1229
|
-
typeof input === "function" ? input() :
|
|
1230
|
-
typeof input === "object" ? bootstrap(input) :
|
|
1231
|
-
Oops$1.BadArgument(typeof input).throw();
|
|
1232
|
-
if (current)
|
|
1233
|
-
mode = onUpdate(current, true) || mode;
|
|
1234
|
-
else if (mode == true)
|
|
1235
|
-
throw Oops$1.MustBeDefined(subject, key);
|
|
1236
|
-
}
|
|
1237
|
-
else
|
|
1238
|
-
mode = false;
|
|
1239
|
-
this.manage(key, current, onUpdate);
|
|
1240
|
-
return () => current;
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
function parent(Expects, required) {
|
|
1244
|
-
return apply(function parent() {
|
|
1245
|
-
const child = this.subject;
|
|
1246
|
-
const expected = Expects.name;
|
|
1247
|
-
const value = Parent.get(this.subject);
|
|
1248
|
-
if (!value) {
|
|
1249
|
-
if (required)
|
|
1250
|
-
throw Oops$1.ParentRequired(expected, child);
|
|
1251
|
-
}
|
|
1252
|
-
else if (!(value instanceof Expects))
|
|
1253
|
-
throw Oops$1.UnexpectedParent(expected, child, value);
|
|
1254
|
-
return { value };
|
|
1255
|
-
});
|
|
1256
1277
|
}
|
|
1257
1278
|
|
|
1258
1279
|
const Oops = issues({
|
|
@@ -1260,35 +1281,32 @@ const Oops = issues({
|
|
|
1260
1281
|
GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1261
1282
|
});
|
|
1262
1283
|
const Active = new WeakMap();
|
|
1263
|
-
class Singleton extends
|
|
1264
|
-
static get current() {
|
|
1265
|
-
return Active.get(this);
|
|
1266
|
-
}
|
|
1284
|
+
class Singleton extends MVC {
|
|
1267
1285
|
static create(...args) {
|
|
1268
1286
|
const Type = this;
|
|
1269
1287
|
if (Active.has(Type))
|
|
1270
1288
|
throw Oops.GlobalExists(this.name);
|
|
1271
|
-
|
|
1289
|
+
const instance = super.create(...args);
|
|
1272
1290
|
Active.set(Type, instance);
|
|
1273
1291
|
return instance;
|
|
1274
1292
|
}
|
|
1275
|
-
static
|
|
1276
|
-
const instance = this
|
|
1293
|
+
static set(updates) {
|
|
1294
|
+
const instance = Active.get(this) || this.create();
|
|
1277
1295
|
instance.import(updates);
|
|
1278
1296
|
return instance.update();
|
|
1279
1297
|
}
|
|
1280
|
-
static
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
static find(strict) {
|
|
1284
|
-
const instance = this.current;
|
|
1285
|
-
if (!instance && strict)
|
|
1298
|
+
static get(arg) {
|
|
1299
|
+
const instance = Active.get(this);
|
|
1300
|
+
if (!instance && arg !== false)
|
|
1286
1301
|
throw Oops.GlobalDoesNotExist(this.name);
|
|
1287
|
-
return
|
|
1302
|
+
return (typeof arg == "string" ?
|
|
1303
|
+
instance[arg] :
|
|
1304
|
+
instance);
|
|
1288
1305
|
}
|
|
1289
1306
|
static reset() {
|
|
1290
|
-
|
|
1291
|
-
|
|
1307
|
+
const current = Active.get(this);
|
|
1308
|
+
if (current)
|
|
1309
|
+
current.destroy();
|
|
1292
1310
|
}
|
|
1293
1311
|
destroy() {
|
|
1294
1312
|
super.destroy();
|
|
@@ -1296,5 +1314,5 @@ class Singleton extends Model {
|
|
|
1296
1314
|
}
|
|
1297
1315
|
}
|
|
1298
1316
|
|
|
1299
|
-
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 };
|
|
1300
1318
|
//# sourceMappingURL=index.esm.js.map
|