@expressive/mvc 0.15.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +108 -153
- package/lib/index.esm.js +550 -555
- package/lib/index.js +549 -559
- package/package.json +1 -1
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,21 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { Suspense } from 'react';
|
|
2
|
+
|
|
3
|
+
class Issue extends Error {
|
|
4
|
+
constructor() {
|
|
5
|
+
super(...arguments);
|
|
6
|
+
// drop first line (error factory) in stack trace.
|
|
7
|
+
this.stack = this.stack.replace(/\n.+/, "");
|
|
8
|
+
}
|
|
9
|
+
warn() {
|
|
10
|
+
console.warn(this.message);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function issues(register) {
|
|
14
|
+
const Library = {};
|
|
15
|
+
for (const name in register)
|
|
16
|
+
Library[name] = (...args) => new Issue(register[name].apply(null, args));
|
|
17
|
+
return Library;
|
|
18
|
+
}
|
|
2
19
|
|
|
3
20
|
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
4
21
|
const UID_CACHE = new WeakMap();
|
|
@@ -14,28 +31,82 @@ function uid(object) {
|
|
|
14
31
|
return uid;
|
|
15
32
|
}
|
|
16
33
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
this.
|
|
34
|
+
const REGISTER$1 = new WeakMap();
|
|
35
|
+
class Subscriber {
|
|
36
|
+
constructor(parent, onUpdate, strict) {
|
|
37
|
+
this.parent = parent;
|
|
38
|
+
this.onUpdate = onUpdate;
|
|
39
|
+
this.strict = strict;
|
|
40
|
+
this.active = false;
|
|
41
|
+
this.dependant = new Set();
|
|
42
|
+
this.watch = new Map();
|
|
43
|
+
const proxy = create(parent.subject);
|
|
44
|
+
const reset = () => this.latest = undefined;
|
|
45
|
+
REGISTER$1.set(proxy, this);
|
|
46
|
+
defineProperty(this, "proxy", {
|
|
47
|
+
configurable: true,
|
|
48
|
+
get() {
|
|
49
|
+
setTimeout(reset, 0);
|
|
50
|
+
return proxy;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
this.clear = parent.addListener(key => {
|
|
54
|
+
if (this.active)
|
|
55
|
+
this.notify(key);
|
|
56
|
+
});
|
|
22
57
|
}
|
|
23
|
-
|
|
24
|
-
|
|
58
|
+
get using() {
|
|
59
|
+
return Array.from(this.watch.keys());
|
|
60
|
+
}
|
|
61
|
+
apply(values, keys) {
|
|
62
|
+
const { waiting, subject } = this.parent;
|
|
63
|
+
this.active = false;
|
|
64
|
+
if (!keys)
|
|
65
|
+
keys = getOwnPropertyNames(subject);
|
|
66
|
+
for (const key of keys)
|
|
67
|
+
if (key in values)
|
|
68
|
+
subject[key] = values[key];
|
|
69
|
+
waiting.add(() => this.active = true);
|
|
70
|
+
}
|
|
71
|
+
follow(key, value) {
|
|
72
|
+
if (value !== undefined)
|
|
73
|
+
this.watch.set(key, value);
|
|
74
|
+
else if (!this.watch.has(key))
|
|
75
|
+
this.watch.set(key, true);
|
|
76
|
+
}
|
|
77
|
+
commit() {
|
|
78
|
+
this.active = true;
|
|
79
|
+
this.dependant.forEach(x => x.commit());
|
|
80
|
+
}
|
|
81
|
+
release() {
|
|
82
|
+
this.clear();
|
|
83
|
+
this.dependant.forEach(x => x.release());
|
|
84
|
+
}
|
|
85
|
+
notify(key) {
|
|
86
|
+
const { parent, watch } = this;
|
|
87
|
+
const handler = watch.get(key);
|
|
88
|
+
if (!handler)
|
|
89
|
+
return;
|
|
90
|
+
if (typeof handler == "function")
|
|
91
|
+
handler();
|
|
92
|
+
const notify = this.onUpdate(key, parent);
|
|
93
|
+
if (notify) {
|
|
94
|
+
parent.waiting.add(update => {
|
|
95
|
+
this.latest = update.filter(k => watch.has(k));
|
|
96
|
+
});
|
|
97
|
+
parent.waiting.add(notify);
|
|
98
|
+
}
|
|
25
99
|
}
|
|
26
100
|
}
|
|
27
|
-
function
|
|
28
|
-
|
|
29
|
-
for (const name in register)
|
|
30
|
-
Library[name] = (...args) => new Issue(register[name].apply(null, args));
|
|
31
|
-
return Library;
|
|
101
|
+
function subscriber(from) {
|
|
102
|
+
return REGISTER$1.get(from);
|
|
32
103
|
}
|
|
33
104
|
|
|
34
|
-
const Oops$
|
|
105
|
+
const Oops$c = issues({
|
|
35
106
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
36
107
|
});
|
|
37
108
|
function suspend(source, key) {
|
|
38
|
-
const error = Oops$
|
|
109
|
+
const error = Oops$c.NotReady(source.subject, key);
|
|
39
110
|
const promise = new Promise(resolve => {
|
|
40
111
|
const release = source.addListener(forKey => {
|
|
41
112
|
if (forKey == key)
|
|
@@ -75,98 +146,87 @@ function mayRetry(fn) {
|
|
|
75
146
|
return compute();
|
|
76
147
|
}
|
|
77
148
|
|
|
78
|
-
const
|
|
79
|
-
|
|
149
|
+
const Parent = new WeakMap();
|
|
150
|
+
const Oops$b = issues({
|
|
151
|
+
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`,
|
|
152
|
+
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
153
|
+
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
80
154
|
});
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
let pending = KEYS.get(self);
|
|
89
|
-
if (!order)
|
|
90
|
-
ORDER.set(self, order = new Map());
|
|
91
|
-
if (!pending)
|
|
92
|
-
KEYS.set(self, pending = new Set());
|
|
93
|
-
const compute = (initial) => {
|
|
94
|
-
try {
|
|
95
|
-
return setter.call(sub.proxy, sub.proxy);
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
Oops$e.Failed(subject, key, initial).warn();
|
|
99
|
-
throw err;
|
|
100
|
-
}
|
|
155
|
+
function getParentForGetInstruction(type, relativeTo, required) {
|
|
156
|
+
const item = getParent(type, relativeTo);
|
|
157
|
+
return (_refresh) => {
|
|
158
|
+
if (item)
|
|
159
|
+
return item;
|
|
160
|
+
if (required)
|
|
161
|
+
throw Oops$b.Required(type.name, relativeTo);
|
|
101
162
|
};
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
163
|
+
}
|
|
164
|
+
function getParent(type, from) {
|
|
165
|
+
const value = Parent.get(from);
|
|
166
|
+
if (value && !(value instanceof type))
|
|
167
|
+
throw Oops$b.Unexpected(type.name, from, value);
|
|
168
|
+
return value;
|
|
169
|
+
}
|
|
170
|
+
function getRecursive(key, from) {
|
|
171
|
+
const context = new WeakMap();
|
|
172
|
+
const { state } = from;
|
|
173
|
+
return (local) => {
|
|
174
|
+
if (!state.has(key))
|
|
175
|
+
throw suspend(from, key);
|
|
176
|
+
if (!local)
|
|
177
|
+
return state.get(key);
|
|
178
|
+
if (!context.has(local)) {
|
|
179
|
+
let reset;
|
|
180
|
+
const init = () => {
|
|
181
|
+
if (reset)
|
|
182
|
+
reset();
|
|
183
|
+
const value = state.get(key);
|
|
184
|
+
if (value && controller(value)) {
|
|
185
|
+
const child = new Subscriber(control(value), local.onUpdate);
|
|
186
|
+
if (local.active)
|
|
187
|
+
child.commit();
|
|
188
|
+
local.dependant.add(child);
|
|
189
|
+
context.set(local, child.proxy);
|
|
190
|
+
reset = () => {
|
|
191
|
+
child.release();
|
|
192
|
+
local.dependant.delete(child);
|
|
193
|
+
context.set(local, undefined);
|
|
194
|
+
reset = undefined;
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
local.follow(key, init);
|
|
199
|
+
init();
|
|
116
200
|
}
|
|
201
|
+
return context.get(local);
|
|
117
202
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
catch (e) {
|
|
132
|
-
throw e;
|
|
133
|
-
}
|
|
134
|
-
finally {
|
|
135
|
-
sub.commit();
|
|
136
|
-
order.set(refresh, order.size);
|
|
137
|
-
}
|
|
203
|
+
}
|
|
204
|
+
function setRecursive(controller, key, initial) {
|
|
205
|
+
const { state, subject } = controller;
|
|
206
|
+
const Type = initial.constructor;
|
|
207
|
+
let get;
|
|
208
|
+
const onUpdate = (next) => {
|
|
209
|
+
state.set(key, next);
|
|
210
|
+
if (!(next instanceof Type))
|
|
211
|
+
throw Oops$b.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
212
|
+
get = getRecursive(key, controller);
|
|
213
|
+
Parent.set(next, subject);
|
|
214
|
+
control(next);
|
|
215
|
+
return true;
|
|
138
216
|
};
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
217
|
+
onUpdate(initial);
|
|
218
|
+
defineProperty(subject, key, {
|
|
219
|
+
set: controller.ref(key, onUpdate),
|
|
220
|
+
get() {
|
|
221
|
+
const local = subscriber(this);
|
|
222
|
+
if (local)
|
|
223
|
+
local.follow(key);
|
|
224
|
+
return get(local);
|
|
144
225
|
}
|
|
145
|
-
|
|
146
|
-
if (value === undefined && required)
|
|
147
|
-
throw suspend(self, key);
|
|
148
|
-
return value;
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
function flush(control) {
|
|
152
|
-
const pending = KEYS.get(control);
|
|
153
|
-
if (!pending || !pending.size)
|
|
154
|
-
return;
|
|
155
|
-
const priority = ORDER.get(control);
|
|
156
|
-
while (pending.size) {
|
|
157
|
-
let compute;
|
|
158
|
-
for (const item of pending)
|
|
159
|
-
if (!compute || priority.get(item) < priority.get(compute))
|
|
160
|
-
compute = item;
|
|
161
|
-
pending.delete(compute);
|
|
162
|
-
const key = INFO.get(compute);
|
|
163
|
-
if (!control.frame.has(key))
|
|
164
|
-
compute();
|
|
165
|
-
}
|
|
166
|
-
pending.clear();
|
|
226
|
+
});
|
|
167
227
|
}
|
|
168
228
|
|
|
169
|
-
const Oops$
|
|
229
|
+
const Oops$a = issues({
|
|
170
230
|
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
171
231
|
});
|
|
172
232
|
function createEffect(model, callback, keys) {
|
|
@@ -180,7 +240,7 @@ function createEffect(model, callback, keys) {
|
|
|
180
240
|
if (unSet instanceof Promise)
|
|
181
241
|
unSet = undefined;
|
|
182
242
|
if (unSet && typeof unSet !== "function")
|
|
183
|
-
throw Oops$
|
|
243
|
+
throw Oops$a.BadCallback();
|
|
184
244
|
}
|
|
185
245
|
function invoke() {
|
|
186
246
|
if (busy)
|
|
@@ -204,10 +264,11 @@ function createEffect(model, callback, keys) {
|
|
|
204
264
|
return invoke;
|
|
205
265
|
});
|
|
206
266
|
}
|
|
207
|
-
const sub = controller
|
|
267
|
+
const sub = new Subscriber(controller, () => invoke);
|
|
208
268
|
model = sub.proxy;
|
|
209
269
|
invoke();
|
|
210
|
-
|
|
270
|
+
sub.commit();
|
|
271
|
+
return () => sub.release();
|
|
211
272
|
});
|
|
212
273
|
}
|
|
213
274
|
function createValueEffect(callback) {
|
|
@@ -223,11 +284,11 @@ function createValueEffect(callback) {
|
|
|
223
284
|
if (typeof out == "function")
|
|
224
285
|
unSet = out;
|
|
225
286
|
else
|
|
226
|
-
throw Oops$
|
|
287
|
+
throw Oops$a.BadCallback();
|
|
227
288
|
};
|
|
228
289
|
}
|
|
229
290
|
|
|
230
|
-
const Oops$
|
|
291
|
+
const Oops$9 = issues({
|
|
231
292
|
Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
|
|
232
293
|
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
233
294
|
StrictUpdate: () => `Expected update but none in progress.`,
|
|
@@ -263,13 +324,13 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
263
324
|
const timeout = (message) => {
|
|
264
325
|
const k = keys ? keys.join(", ") : "any";
|
|
265
326
|
removeListener();
|
|
266
|
-
reject(Oops$
|
|
327
|
+
reject(Oops$9.Timeout(k, message));
|
|
267
328
|
};
|
|
268
329
|
const removeListener = control(source, controller => {
|
|
269
330
|
const pending = controller.frame;
|
|
270
331
|
if (keys === null) {
|
|
271
332
|
if (pending.size)
|
|
272
|
-
reject(Oops$
|
|
333
|
+
reject(Oops$9.StrictNoUpdate());
|
|
273
334
|
else
|
|
274
335
|
resolve(null);
|
|
275
336
|
return;
|
|
@@ -277,7 +338,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
277
338
|
if (keys) {
|
|
278
339
|
if (keys.length) {
|
|
279
340
|
if (arg2 === 0 && single && !pending.has(keys[0])) {
|
|
280
|
-
reject(Oops$
|
|
341
|
+
reject(Oops$9.KeysExpected(keys[0]));
|
|
281
342
|
return;
|
|
282
343
|
}
|
|
283
344
|
else
|
|
@@ -289,7 +350,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
289
350
|
}
|
|
290
351
|
}
|
|
291
352
|
else if (!pending.size && arg1 === true || arg2 === 0) {
|
|
292
|
-
reject(Oops$
|
|
353
|
+
reject(Oops$9.StrictUpdate());
|
|
293
354
|
return;
|
|
294
355
|
}
|
|
295
356
|
else
|
|
@@ -312,67 +373,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
312
373
|
});
|
|
313
374
|
}
|
|
314
375
|
|
|
315
|
-
const
|
|
316
|
-
class Subscriber {
|
|
317
|
-
constructor(parent, onUpdate) {
|
|
318
|
-
this.parent = parent;
|
|
319
|
-
this.onUpdate = onUpdate;
|
|
320
|
-
this.active = false;
|
|
321
|
-
this.dependant = new Set();
|
|
322
|
-
this.watch = new Map();
|
|
323
|
-
const proxy = create(parent.subject);
|
|
324
|
-
const reset = () => this.latest = undefined;
|
|
325
|
-
REGISTER$1.set(proxy, this);
|
|
326
|
-
defineProperty(this, "proxy", {
|
|
327
|
-
configurable: true,
|
|
328
|
-
get() {
|
|
329
|
-
setTimeout(reset, 0);
|
|
330
|
-
return proxy;
|
|
331
|
-
}
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
|
-
get using() {
|
|
335
|
-
return Array.from(this.watch.keys());
|
|
336
|
-
}
|
|
337
|
-
add(key, value) {
|
|
338
|
-
if (value !== undefined)
|
|
339
|
-
this.watch.set(key, value);
|
|
340
|
-
else if (!this.watch.has(key))
|
|
341
|
-
this.watch.set(key, true);
|
|
342
|
-
}
|
|
343
|
-
commit() {
|
|
344
|
-
const release = this.parent.addListener(key => {
|
|
345
|
-
if (this.active)
|
|
346
|
-
this.onEvent(key);
|
|
347
|
-
});
|
|
348
|
-
this.active = true;
|
|
349
|
-
this.dependant.forEach(x => x.commit());
|
|
350
|
-
return this.release = () => {
|
|
351
|
-
this.dependant.forEach(x => x.release());
|
|
352
|
-
release();
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
onEvent(key) {
|
|
356
|
-
const { parent, watch } = this;
|
|
357
|
-
let handler = watch.get(key);
|
|
358
|
-
if (typeof handler == "function")
|
|
359
|
-
handler = handler();
|
|
360
|
-
if (handler) {
|
|
361
|
-
const notify = this.onUpdate(key, parent);
|
|
362
|
-
if (notify) {
|
|
363
|
-
parent.waiting.add(update => {
|
|
364
|
-
this.latest = update.filter(k => watch.has(k));
|
|
365
|
-
});
|
|
366
|
-
parent.waiting.add(notify);
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
function subscriber(from) {
|
|
372
|
-
return REGISTER$1.get(from);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const Oops$b = issues({
|
|
376
|
+
const Oops$8 = issues({
|
|
376
377
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
377
378
|
});
|
|
378
379
|
class Model {
|
|
@@ -430,7 +431,7 @@ class Model {
|
|
|
430
431
|
return {
|
|
431
432
|
then: (callback) => {
|
|
432
433
|
if (!callback)
|
|
433
|
-
throw Oops$
|
|
434
|
+
throw Oops$8.NoChaining();
|
|
434
435
|
controller.waiting.add(callback);
|
|
435
436
|
}
|
|
436
437
|
};
|
|
@@ -463,11 +464,150 @@ class Model {
|
|
|
463
464
|
maybe.prototype instanceof this);
|
|
464
465
|
}
|
|
465
466
|
}
|
|
466
|
-
defineProperty(Model.prototype, "toString", {
|
|
467
|
-
value() {
|
|
468
|
-
return this.constructor.name;
|
|
469
|
-
}
|
|
470
|
-
});
|
|
467
|
+
defineProperty(Model.prototype, "toString", {
|
|
468
|
+
value() {
|
|
469
|
+
return this.constructor.name;
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
const FindInstruction = new WeakMap([
|
|
473
|
+
[Model, getParentForGetInstruction]
|
|
474
|
+
]);
|
|
475
|
+
|
|
476
|
+
const Oops$7 = issues({
|
|
477
|
+
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
478
|
+
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
479
|
+
});
|
|
480
|
+
function get(arg0, arg1) {
|
|
481
|
+
return add(function get(key) {
|
|
482
|
+
const { subject, state } = this;
|
|
483
|
+
// Easy mistake, using a peer, will always be unresolved.
|
|
484
|
+
if (typeof arg0 == "symbol")
|
|
485
|
+
throw Oops$7.PeerNotAllowed(subject, key);
|
|
486
|
+
let source;
|
|
487
|
+
const sourceRequired = arg1 !== false;
|
|
488
|
+
if (arg0 instanceof Model) {
|
|
489
|
+
source = () => arg0;
|
|
490
|
+
if (typeof arg1 !== "function")
|
|
491
|
+
throw new Error(`Factory argument cannot be ${arg1}`);
|
|
492
|
+
}
|
|
493
|
+
else if (Model.isTypeof(arg0)) {
|
|
494
|
+
source = find(arg0, subject, sourceRequired);
|
|
495
|
+
}
|
|
496
|
+
else if (typeof arg0 == "function") {
|
|
497
|
+
arg1 = arg0.call(subject, key, subject);
|
|
498
|
+
source = () => subject;
|
|
499
|
+
}
|
|
500
|
+
if (typeof arg1 == "function")
|
|
501
|
+
return getComputed(key, this, source, arg1);
|
|
502
|
+
else {
|
|
503
|
+
const init = source((got) => {
|
|
504
|
+
state.set(key, got);
|
|
505
|
+
this.update(key);
|
|
506
|
+
});
|
|
507
|
+
// TODO: remove fixes suspense test
|
|
508
|
+
if (init || arg1 === false)
|
|
509
|
+
state.set(key, init);
|
|
510
|
+
return getRecursive(key, this);
|
|
511
|
+
}
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
function getComputed(key, parent, source, setter) {
|
|
515
|
+
const { state } = parent;
|
|
516
|
+
let sub;
|
|
517
|
+
let order = ORDER.get(parent);
|
|
518
|
+
let pending = KEYS.get(parent);
|
|
519
|
+
let instance;
|
|
520
|
+
if (!order)
|
|
521
|
+
ORDER.set(parent, order = new Map());
|
|
522
|
+
if (!pending)
|
|
523
|
+
KEYS.set(parent, pending = new Set());
|
|
524
|
+
const compute = (initial) => {
|
|
525
|
+
try {
|
|
526
|
+
return setter.call(sub.proxy, sub.proxy);
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
Oops$7.Failed(instance, key, initial).warn();
|
|
530
|
+
throw err;
|
|
531
|
+
}
|
|
532
|
+
};
|
|
533
|
+
const create = () => {
|
|
534
|
+
// TODO: replace create with a cleanup function
|
|
535
|
+
const got = source(create);
|
|
536
|
+
if (!got)
|
|
537
|
+
throw suspend(parent, key);
|
|
538
|
+
instance = got;
|
|
539
|
+
sub = new Subscriber(control(instance), (_, control) => {
|
|
540
|
+
if (control !== parent)
|
|
541
|
+
refresh();
|
|
542
|
+
else
|
|
543
|
+
pending.add(refresh);
|
|
544
|
+
});
|
|
545
|
+
sub.watch.set(key, false);
|
|
546
|
+
try {
|
|
547
|
+
const value = compute(true);
|
|
548
|
+
state.set(key, value);
|
|
549
|
+
return value;
|
|
550
|
+
}
|
|
551
|
+
finally {
|
|
552
|
+
sub.commit();
|
|
553
|
+
order.set(refresh, order.size);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
const refresh = () => {
|
|
557
|
+
let value;
|
|
558
|
+
try {
|
|
559
|
+
value = compute(false);
|
|
560
|
+
}
|
|
561
|
+
catch (e) {
|
|
562
|
+
console.error(e);
|
|
563
|
+
}
|
|
564
|
+
finally {
|
|
565
|
+
if (state.get(key) !== value) {
|
|
566
|
+
state.set(key, value);
|
|
567
|
+
parent.update(key);
|
|
568
|
+
return value;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
};
|
|
572
|
+
INFO.set(refresh, key);
|
|
573
|
+
return () => {
|
|
574
|
+
if (pending.has(refresh)) {
|
|
575
|
+
pending.delete(refresh);
|
|
576
|
+
refresh();
|
|
577
|
+
}
|
|
578
|
+
return sub ? state.get(key) : create();
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
const INFO = new WeakMap();
|
|
582
|
+
const KEYS = new WeakMap();
|
|
583
|
+
const ORDER = new WeakMap();
|
|
584
|
+
function flush(control) {
|
|
585
|
+
const pending = KEYS.get(control);
|
|
586
|
+
if (!pending || !pending.size)
|
|
587
|
+
return;
|
|
588
|
+
const priority = ORDER.get(control);
|
|
589
|
+
while (pending.size) {
|
|
590
|
+
let compute;
|
|
591
|
+
for (const item of pending)
|
|
592
|
+
if (!compute || priority.get(item) < priority.get(compute))
|
|
593
|
+
compute = item;
|
|
594
|
+
pending.delete(compute);
|
|
595
|
+
const key = INFO.get(compute);
|
|
596
|
+
if (!control.frame.has(key))
|
|
597
|
+
compute();
|
|
598
|
+
}
|
|
599
|
+
pending.clear();
|
|
600
|
+
}
|
|
601
|
+
// TODO: collapse this function when MVC is merged into Model.
|
|
602
|
+
function find(type, relativeTo, required) {
|
|
603
|
+
let T = type;
|
|
604
|
+
do {
|
|
605
|
+
T = getPrototypeOf(T);
|
|
606
|
+
const getter = FindInstruction.get(T);
|
|
607
|
+
if (getter)
|
|
608
|
+
return getter(type, relativeTo, required);
|
|
609
|
+
} while (T.prototype instanceof Model);
|
|
610
|
+
}
|
|
471
611
|
|
|
472
612
|
const REGISTER = new WeakMap();
|
|
473
613
|
const PENDING = new Map();
|
|
@@ -479,9 +619,6 @@ class Control {
|
|
|
479
619
|
this.followers = new Set();
|
|
480
620
|
REGISTER.set(subject, this);
|
|
481
621
|
}
|
|
482
|
-
subscribe(callback) {
|
|
483
|
-
return new Subscriber(this, callback);
|
|
484
|
-
}
|
|
485
622
|
watch(key) {
|
|
486
623
|
const { subject, state } = this;
|
|
487
624
|
const { value } = getOwnPropertyDescriptor(subject, key);
|
|
@@ -492,7 +629,7 @@ class Control {
|
|
|
492
629
|
if (instruction) {
|
|
493
630
|
delete subject[key];
|
|
494
631
|
PENDING.delete(value);
|
|
495
|
-
instruction
|
|
632
|
+
instruction(this, key);
|
|
496
633
|
}
|
|
497
634
|
return;
|
|
498
635
|
}
|
|
@@ -506,9 +643,13 @@ class Control {
|
|
|
506
643
|
set: this.ref(key),
|
|
507
644
|
get() {
|
|
508
645
|
const sub = subscriber(this);
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
646
|
+
const value = state.get(key);
|
|
647
|
+
if (sub) {
|
|
648
|
+
sub.follow(key);
|
|
649
|
+
if (value === undefined && sub.strict)
|
|
650
|
+
throw suspend(this, key);
|
|
651
|
+
}
|
|
652
|
+
return value;
|
|
512
653
|
}
|
|
513
654
|
});
|
|
514
655
|
}
|
|
@@ -566,6 +707,8 @@ class Control {
|
|
|
566
707
|
listeners.forEach(x => x(null, this));
|
|
567
708
|
}
|
|
568
709
|
}
|
|
710
|
+
Control.get = controller;
|
|
711
|
+
Control.for = control;
|
|
569
712
|
function controller(from) {
|
|
570
713
|
if ("is" in from)
|
|
571
714
|
from = from.is;
|
|
@@ -595,68 +738,6 @@ function control(subject, cb) {
|
|
|
595
738
|
return cb ? cb(control) : control;
|
|
596
739
|
}
|
|
597
740
|
|
|
598
|
-
const Parent = new WeakMap();
|
|
599
|
-
const Oops$a = issues({
|
|
600
|
-
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
|
|
601
|
-
});
|
|
602
|
-
function getRecursive(key, from) {
|
|
603
|
-
const context = new WeakMap();
|
|
604
|
-
const { state } = from;
|
|
605
|
-
return (local) => {
|
|
606
|
-
if (!local)
|
|
607
|
-
return state.get(key);
|
|
608
|
-
if (!context.has(local)) {
|
|
609
|
-
let reset;
|
|
610
|
-
const init = () => {
|
|
611
|
-
if (reset)
|
|
612
|
-
reset();
|
|
613
|
-
const value = state.get(key);
|
|
614
|
-
if (value && controller(value)) {
|
|
615
|
-
const child = control(value).subscribe(local.onUpdate);
|
|
616
|
-
if (local.active)
|
|
617
|
-
child.commit();
|
|
618
|
-
local.dependant.add(child);
|
|
619
|
-
context.set(local, child.proxy);
|
|
620
|
-
reset = () => {
|
|
621
|
-
child.release();
|
|
622
|
-
local.dependant.delete(child);
|
|
623
|
-
context.set(local, undefined);
|
|
624
|
-
reset = undefined;
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
|
-
return true;
|
|
628
|
-
};
|
|
629
|
-
local.add(key, init);
|
|
630
|
-
init();
|
|
631
|
-
}
|
|
632
|
-
return context.get(local);
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
function setRecursive(controller, key, initial) {
|
|
636
|
-
const { state, subject } = controller;
|
|
637
|
-
const Type = initial.constructor;
|
|
638
|
-
let get;
|
|
639
|
-
const onUpdate = (next) => {
|
|
640
|
-
state.set(key, next);
|
|
641
|
-
if (!(next instanceof Type))
|
|
642
|
-
throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
643
|
-
get = getRecursive(key, controller);
|
|
644
|
-
Parent.set(next, subject);
|
|
645
|
-
control(next);
|
|
646
|
-
return true;
|
|
647
|
-
};
|
|
648
|
-
onUpdate(initial);
|
|
649
|
-
defineProperty(subject, key, {
|
|
650
|
-
set: controller.ref(key, onUpdate),
|
|
651
|
-
get() {
|
|
652
|
-
const local = subscriber(this);
|
|
653
|
-
if (local)
|
|
654
|
-
local.add(key);
|
|
655
|
-
return get(local);
|
|
656
|
-
}
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
|
|
660
741
|
/**
|
|
661
742
|
* Run instruction as controller sets itself up.
|
|
662
743
|
* This will specialize the behavior of a given property.
|
|
@@ -664,53 +745,42 @@ function setRecursive(controller, key, initial) {
|
|
|
664
745
|
function add(instruction, label) {
|
|
665
746
|
const name = label || instruction.name || "pending";
|
|
666
747
|
const placeholder = Symbol(`${name} instruction`);
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
748
|
+
PENDING.set(placeholder, (control, key) => {
|
|
749
|
+
let output = instruction.call(control, key, control);
|
|
750
|
+
if (!output)
|
|
751
|
+
return undefined;
|
|
670
752
|
if (typeof output == "function")
|
|
671
753
|
output = { get: output };
|
|
672
|
-
if (typeof output != "object")
|
|
673
|
-
return;
|
|
674
|
-
if ("explicit" in output && output.explicit) {
|
|
675
|
-
defineProperty(subject, key, output);
|
|
676
|
-
return false;
|
|
677
|
-
}
|
|
678
|
-
let { get: onGet, set: onSet, suspend: shouldSuspend } = output;
|
|
679
754
|
if ("value" in output)
|
|
680
|
-
state.set(key, output.value);
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
if (destroy)
|
|
686
|
-
this.addListener((key) => {
|
|
687
|
-
if (key == null)
|
|
688
|
-
destroy();
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
const control = this;
|
|
692
|
-
defineProperty(subject, key, {
|
|
693
|
-
enumerable: output.enumerable,
|
|
694
|
-
set: onSet === false
|
|
755
|
+
control.state.set(key, output.value);
|
|
756
|
+
let { enumerable, get, set } = output;
|
|
757
|
+
defineProperty(control.subject, key, {
|
|
758
|
+
enumerable,
|
|
759
|
+
set: set === false
|
|
695
760
|
? undefined
|
|
696
|
-
:
|
|
761
|
+
: control.ref(key, set),
|
|
697
762
|
get() {
|
|
698
|
-
if (!state.has(key) && shouldSuspend)
|
|
699
|
-
throw suspend(control, key);
|
|
700
763
|
const local = subscriber(this);
|
|
701
764
|
if (local)
|
|
702
|
-
local.
|
|
703
|
-
|
|
704
|
-
?
|
|
705
|
-
|
|
765
|
+
local.follow(key);
|
|
766
|
+
try {
|
|
767
|
+
const value = get ? get(local) : control.state.get(key);
|
|
768
|
+
if (value === undefined && local && local.strict === true)
|
|
769
|
+
throw suspend(control, key);
|
|
770
|
+
return value;
|
|
771
|
+
}
|
|
772
|
+
catch (err) {
|
|
773
|
+
if (err instanceof Promise && local && local.strict === false)
|
|
774
|
+
return;
|
|
775
|
+
throw err;
|
|
776
|
+
}
|
|
706
777
|
}
|
|
707
778
|
});
|
|
708
|
-
}
|
|
709
|
-
PENDING.set(placeholder, setup);
|
|
779
|
+
});
|
|
710
780
|
return placeholder;
|
|
711
781
|
}
|
|
712
782
|
|
|
713
|
-
|
|
783
|
+
/******************************************************************************
|
|
714
784
|
Copyright (c) Microsoft Corporation.
|
|
715
785
|
|
|
716
786
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
@@ -735,7 +805,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
735
805
|
});
|
|
736
806
|
}
|
|
737
807
|
|
|
738
|
-
const Oops$
|
|
808
|
+
const Oops$6 = issues({
|
|
739
809
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
740
810
|
});
|
|
741
811
|
function run(task) {
|
|
@@ -743,7 +813,7 @@ function run(task) {
|
|
|
743
813
|
let pending = false;
|
|
744
814
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
745
815
|
if (pending)
|
|
746
|
-
return Promise.reject(Oops$
|
|
816
|
+
return Promise.reject(Oops$6.DuplicatePending(key));
|
|
747
817
|
pending = true;
|
|
748
818
|
this.update(key);
|
|
749
819
|
try {
|
|
@@ -765,106 +835,6 @@ function run(task) {
|
|
|
765
835
|
});
|
|
766
836
|
}
|
|
767
837
|
|
|
768
|
-
const Oops$8 = issues({
|
|
769
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
770
|
-
});
|
|
771
|
-
function factoryMode(self, value, key, required) {
|
|
772
|
-
const { subject, state } = self;
|
|
773
|
-
let pending;
|
|
774
|
-
let error;
|
|
775
|
-
if (value instanceof Promise) {
|
|
776
|
-
state.set(key, undefined);
|
|
777
|
-
pending = value
|
|
778
|
-
.catch(err => error = err)
|
|
779
|
-
.then(val => {
|
|
780
|
-
state.set(key, val);
|
|
781
|
-
return val;
|
|
782
|
-
})
|
|
783
|
-
.finally(() => {
|
|
784
|
-
pending = undefined;
|
|
785
|
-
self.update(key);
|
|
786
|
-
});
|
|
787
|
-
}
|
|
788
|
-
else
|
|
789
|
-
state.set(key, value);
|
|
790
|
-
const suspend = () => {
|
|
791
|
-
if (required === false)
|
|
792
|
-
return undefined;
|
|
793
|
-
const issue = Oops$8.NotReady(subject, key);
|
|
794
|
-
assign(pending, {
|
|
795
|
-
message: issue.message,
|
|
796
|
-
stack: issue.stack
|
|
797
|
-
});
|
|
798
|
-
throw pending;
|
|
799
|
-
};
|
|
800
|
-
return () => {
|
|
801
|
-
if (error)
|
|
802
|
-
throw error;
|
|
803
|
-
if (pending)
|
|
804
|
-
return suspend();
|
|
805
|
-
if (state.has(key))
|
|
806
|
-
return state.get(key);
|
|
807
|
-
};
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
const Oops$7 = issues({
|
|
811
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
812
|
-
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
813
|
-
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
814
|
-
});
|
|
815
|
-
function get(arg0, arg1, arg2) {
|
|
816
|
-
return add(function get(key) {
|
|
817
|
-
const { subject } = this;
|
|
818
|
-
const computeRequired = arg1 === true || arg2 === true;
|
|
819
|
-
const factoryRequired = arg1 !== false && arg2 !== false;
|
|
820
|
-
let getter;
|
|
821
|
-
// Easy mistake, using a peer, will always be unresolved.
|
|
822
|
-
if (typeof arg0 == "symbol")
|
|
823
|
-
throw Oops$7.PeerNotAllowed(subject, key);
|
|
824
|
-
// if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
|
|
825
|
-
// throw Oops.BadSource(subject, key, arg0);
|
|
826
|
-
this.state.set(key, undefined);
|
|
827
|
-
const init = () => {
|
|
828
|
-
let source = this;
|
|
829
|
-
let setter;
|
|
830
|
-
if (typeof arg0 == "function") {
|
|
831
|
-
let result = mayRetry(arg0.bind(subject, key, subject));
|
|
832
|
-
if (typeof result == "function")
|
|
833
|
-
setter = result;
|
|
834
|
-
else {
|
|
835
|
-
getter = factoryMode(this, result, key, factoryRequired);
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
else if (arg0 instanceof Promise) {
|
|
840
|
-
getter = factoryMode(this, arg0, key, factoryRequired);
|
|
841
|
-
return;
|
|
842
|
-
}
|
|
843
|
-
else if (typeof arg1 == "function") {
|
|
844
|
-
// replace source controller in-case it is different
|
|
845
|
-
source = control(arg0);
|
|
846
|
-
setter = arg1;
|
|
847
|
-
}
|
|
848
|
-
else
|
|
849
|
-
throw new Error(`Factory argument cannot be ${arg1}`);
|
|
850
|
-
getter = computeMode(this, source, setter, key, computeRequired);
|
|
851
|
-
};
|
|
852
|
-
if (typeof arg0 == "function" && computeRequired)
|
|
853
|
-
try {
|
|
854
|
-
init();
|
|
855
|
-
}
|
|
856
|
-
catch (err) {
|
|
857
|
-
Oops$7.ComputeFailed(subject, key).warn();
|
|
858
|
-
throw err;
|
|
859
|
-
}
|
|
860
|
-
return () => {
|
|
861
|
-
if (!getter)
|
|
862
|
-
init();
|
|
863
|
-
return getter();
|
|
864
|
-
};
|
|
865
|
-
});
|
|
866
|
-
}
|
|
867
|
-
|
|
868
838
|
function ref(arg, mapper) {
|
|
869
839
|
return add(function ref(key) {
|
|
870
840
|
let value = {};
|
|
@@ -884,7 +854,7 @@ function ref(arg, mapper) {
|
|
|
884
854
|
value: createRef(this, key)
|
|
885
855
|
});
|
|
886
856
|
});
|
|
887
|
-
|
|
857
|
+
defineProperty(this.subject, key, { value });
|
|
888
858
|
});
|
|
889
859
|
}
|
|
890
860
|
function createRef(src, key, cb) {
|
|
@@ -896,16 +866,78 @@ function createRef(src, key, cb) {
|
|
|
896
866
|
return refObjectFunction;
|
|
897
867
|
}
|
|
898
868
|
|
|
869
|
+
const Oops$5 = issues({
|
|
870
|
+
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
871
|
+
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
872
|
+
});
|
|
899
873
|
function set(value, argument) {
|
|
900
|
-
if (!(1 in arguments)) {
|
|
901
|
-
argument = value;
|
|
902
|
-
value = undefined;
|
|
903
|
-
}
|
|
904
874
|
return add(function set(key) {
|
|
875
|
+
const { state, subject } = this;
|
|
876
|
+
if (typeof value == "function" || value instanceof Promise) {
|
|
877
|
+
const required = argument !== false;
|
|
878
|
+
let getter;
|
|
879
|
+
const init = () => {
|
|
880
|
+
try {
|
|
881
|
+
if (typeof value == "function")
|
|
882
|
+
value = mayRetry(value.bind(subject, key, subject));
|
|
883
|
+
let pending;
|
|
884
|
+
let error;
|
|
885
|
+
if (value instanceof Promise) {
|
|
886
|
+
state.set(key, undefined);
|
|
887
|
+
pending = value
|
|
888
|
+
.catch(err => error = err)
|
|
889
|
+
.then(val => {
|
|
890
|
+
state.set(key, val);
|
|
891
|
+
return val;
|
|
892
|
+
})
|
|
893
|
+
.finally(() => {
|
|
894
|
+
pending = undefined;
|
|
895
|
+
this.update(key);
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
else
|
|
899
|
+
state.set(key, value);
|
|
900
|
+
const suspend = () => {
|
|
901
|
+
if (required === false)
|
|
902
|
+
return undefined;
|
|
903
|
+
const issue = Oops$5.NotReady(subject, key);
|
|
904
|
+
assign(pending, {
|
|
905
|
+
message: issue.message,
|
|
906
|
+
stack: issue.stack
|
|
907
|
+
});
|
|
908
|
+
throw pending;
|
|
909
|
+
};
|
|
910
|
+
getter = () => {
|
|
911
|
+
if (error)
|
|
912
|
+
throw error;
|
|
913
|
+
if (pending)
|
|
914
|
+
return suspend();
|
|
915
|
+
if (state.has(key))
|
|
916
|
+
return state.get(key);
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
catch (err) {
|
|
920
|
+
Oops$5.ComputeFailed(subject, key).warn();
|
|
921
|
+
throw err;
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
if (argument === true)
|
|
925
|
+
init();
|
|
926
|
+
return () => {
|
|
927
|
+
if (!getter)
|
|
928
|
+
init();
|
|
929
|
+
return getter();
|
|
930
|
+
};
|
|
931
|
+
}
|
|
905
932
|
if (value !== undefined)
|
|
906
|
-
|
|
933
|
+
state.set(key, value);
|
|
907
934
|
return {
|
|
908
|
-
|
|
935
|
+
get: () => {
|
|
936
|
+
if (state.has(key))
|
|
937
|
+
return state.get(key);
|
|
938
|
+
else
|
|
939
|
+
throw suspend(this, key);
|
|
940
|
+
},
|
|
909
941
|
set: typeof argument == "function"
|
|
910
942
|
? createValueEffect(argument)
|
|
911
943
|
: undefined
|
|
@@ -949,7 +981,7 @@ function keyed(control, property, initial) {
|
|
|
949
981
|
}
|
|
950
982
|
}
|
|
951
983
|
}
|
|
952
|
-
local.
|
|
984
|
+
local.follow(property, false);
|
|
953
985
|
local.dependant.add({
|
|
954
986
|
commit() {
|
|
955
987
|
if (using.size === 0)
|
|
@@ -965,6 +997,12 @@ function keyed(control, property, initial) {
|
|
|
965
997
|
context.set(local, proxy);
|
|
966
998
|
return proxy;
|
|
967
999
|
}
|
|
1000
|
+
control.addListener(key => {
|
|
1001
|
+
if (key === null) {
|
|
1002
|
+
update.clear();
|
|
1003
|
+
context.clear();
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
968
1006
|
return {
|
|
969
1007
|
value: initial,
|
|
970
1008
|
get(local) {
|
|
@@ -977,10 +1015,6 @@ function keyed(control, property, initial) {
|
|
|
977
1015
|
managed = init(next);
|
|
978
1016
|
context.clear();
|
|
979
1017
|
emit(ANY);
|
|
980
|
-
},
|
|
981
|
-
destroy() {
|
|
982
|
-
update.clear();
|
|
983
|
-
context.clear();
|
|
984
1018
|
}
|
|
985
1019
|
};
|
|
986
1020
|
}
|
|
@@ -1059,11 +1093,11 @@ function createProxy(emit, watch) {
|
|
|
1059
1093
|
};
|
|
1060
1094
|
}
|
|
1061
1095
|
|
|
1062
|
-
const Oops$
|
|
1096
|
+
const Oops$4 = issues({
|
|
1063
1097
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1064
1098
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
1065
1099
|
});
|
|
1066
|
-
function use
|
|
1100
|
+
function use(input, argument) {
|
|
1067
1101
|
return add(function use(key) {
|
|
1068
1102
|
const { state, subject } = this;
|
|
1069
1103
|
const required = argument !== false;
|
|
@@ -1075,7 +1109,7 @@ function use$1(input, argument) {
|
|
|
1075
1109
|
input = new input();
|
|
1076
1110
|
}
|
|
1077
1111
|
else if (input && typeof input !== "object")
|
|
1078
|
-
throw Oops$
|
|
1112
|
+
throw Oops$4.BadArgument(typeof input);
|
|
1079
1113
|
if (input instanceof Map || input instanceof Set)
|
|
1080
1114
|
return keyed(this, key, input);
|
|
1081
1115
|
const onUpdate = (next) => {
|
|
@@ -1092,7 +1126,7 @@ function use$1(input, argument) {
|
|
|
1092
1126
|
const suspend = () => {
|
|
1093
1127
|
if (required === false)
|
|
1094
1128
|
return;
|
|
1095
|
-
const issue = Oops$
|
|
1129
|
+
const issue = Oops$4.NotReady(subject, key);
|
|
1096
1130
|
assign(pending, {
|
|
1097
1131
|
message: issue.message,
|
|
1098
1132
|
stack: issue.stack
|
|
@@ -1137,33 +1171,11 @@ function use$1(input, argument) {
|
|
|
1137
1171
|
});
|
|
1138
1172
|
}
|
|
1139
1173
|
|
|
1140
|
-
|
|
1141
|
-
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
1142
|
-
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
1143
|
-
});
|
|
1144
|
-
function has(Type, required) {
|
|
1145
|
-
return add(function parent() {
|
|
1146
|
-
const child = this.subject;
|
|
1147
|
-
const value = Parent.get(child);
|
|
1148
|
-
const expected = Type.name;
|
|
1149
|
-
if (!value) {
|
|
1150
|
-
if (required !== false)
|
|
1151
|
-
throw Oops$5.Required(expected, child);
|
|
1152
|
-
}
|
|
1153
|
-
else if (!(value instanceof Type))
|
|
1154
|
-
throw Oops$5.Unexpected(expected, child, value);
|
|
1155
|
-
return { value };
|
|
1156
|
-
});
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
const Oops$4 = issues({
|
|
1160
|
-
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1161
|
-
});
|
|
1162
|
-
class Lookup {
|
|
1174
|
+
class Register {
|
|
1163
1175
|
constructor() {
|
|
1164
1176
|
this.table = new Map();
|
|
1165
1177
|
}
|
|
1166
|
-
|
|
1178
|
+
has(T) {
|
|
1167
1179
|
let key = this.table.get(T);
|
|
1168
1180
|
if (!key) {
|
|
1169
1181
|
key = Symbol(T.name);
|
|
@@ -1172,22 +1184,9 @@ class Lookup {
|
|
|
1172
1184
|
return key;
|
|
1173
1185
|
}
|
|
1174
1186
|
get(Type) {
|
|
1175
|
-
return this[this.
|
|
1176
|
-
}
|
|
1177
|
-
has(key, input, callback) {
|
|
1178
|
-
if (MVC.isTypeof(input) && input.global)
|
|
1179
|
-
return input.new();
|
|
1180
|
-
if (this.register.get(key) === input)
|
|
1181
|
-
return typeof input == "object"
|
|
1182
|
-
? input
|
|
1183
|
-
: this.get(input);
|
|
1184
|
-
const instance = this.add(input);
|
|
1185
|
-
this.register.set(key, input);
|
|
1186
|
-
if (callback)
|
|
1187
|
-
callback(instance);
|
|
1188
|
-
return instance;
|
|
1187
|
+
return this[this.has(Type)];
|
|
1189
1188
|
}
|
|
1190
|
-
add(input) {
|
|
1189
|
+
add(input, key) {
|
|
1191
1190
|
let writable = true;
|
|
1192
1191
|
let T;
|
|
1193
1192
|
let I;
|
|
@@ -1196,12 +1195,12 @@ class Lookup {
|
|
|
1196
1195
|
I = new input();
|
|
1197
1196
|
}
|
|
1198
1197
|
else {
|
|
1199
|
-
I = input;
|
|
1198
|
+
I = input.is;
|
|
1200
1199
|
T = I.constructor;
|
|
1201
1200
|
writable = false;
|
|
1202
1201
|
}
|
|
1203
1202
|
do {
|
|
1204
|
-
const key = this.
|
|
1203
|
+
const key = this.has(T);
|
|
1205
1204
|
defineProperty(this, key, {
|
|
1206
1205
|
configurable: true,
|
|
1207
1206
|
value: this.hasOwnProperty(key) ? null : I,
|
|
@@ -1209,6 +1208,8 @@ class Lookup {
|
|
|
1209
1208
|
});
|
|
1210
1209
|
T = getPrototypeOf(T);
|
|
1211
1210
|
} while (T !== Model);
|
|
1211
|
+
if (key !== undefined)
|
|
1212
|
+
this.register.set(key, input);
|
|
1212
1213
|
return I;
|
|
1213
1214
|
}
|
|
1214
1215
|
push() {
|
|
@@ -1222,52 +1223,74 @@ class Lookup {
|
|
|
1222
1223
|
const entry = getOwnPropertyDescriptor(this, key);
|
|
1223
1224
|
if (entry.writable && entry.value)
|
|
1224
1225
|
items.add(entry.value);
|
|
1226
|
+
delete this[key];
|
|
1225
1227
|
}
|
|
1226
1228
|
for (const model of items)
|
|
1227
1229
|
model.end();
|
|
1228
1230
|
}
|
|
1231
|
+
delete(instance) {
|
|
1232
|
+
for (const key of getOwnPropertySymbols(this)) {
|
|
1233
|
+
const entry = getOwnPropertyDescriptor(this, key);
|
|
1234
|
+
if (entry.value === instance)
|
|
1235
|
+
delete this[key];
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
const Global$1 = new Register();
|
|
1240
|
+
|
|
1241
|
+
const Oops$3 = issues({
|
|
1242
|
+
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`,
|
|
1243
|
+
DoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.new() before attempting to access, or consider using ${name}.use() instead.`,
|
|
1244
|
+
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1245
|
+
});
|
|
1246
|
+
const LookupContext = React.createContext(Global$1);
|
|
1247
|
+
function useLookup() {
|
|
1248
|
+
try {
|
|
1249
|
+
return React.useContext(LookupContext);
|
|
1250
|
+
}
|
|
1251
|
+
catch (err) {
|
|
1252
|
+
return Global$1;
|
|
1253
|
+
}
|
|
1229
1254
|
}
|
|
1230
|
-
const LookupContext = React.createContext(new Lookup());
|
|
1231
|
-
const useLookup = () => React.useContext(LookupContext);
|
|
1232
1255
|
function useContext(Type, required) {
|
|
1233
1256
|
const instance = useLookup().get(Type);
|
|
1234
1257
|
if (!instance && required !== false)
|
|
1235
|
-
throw
|
|
1258
|
+
throw MVC.isTypeof(Type) && Type.global
|
|
1259
|
+
? Oops$3.DoesNotExist(Type.name)
|
|
1260
|
+
: Oops$3.NotFound(Type.name);
|
|
1236
1261
|
return instance;
|
|
1237
1262
|
}
|
|
1238
1263
|
|
|
1239
|
-
const Oops$
|
|
1264
|
+
const Oops$2 = issues({
|
|
1240
1265
|
NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
1241
|
-
AmbientRequired: (requested, requester
|
|
1266
|
+
AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
|
|
1242
1267
|
});
|
|
1243
1268
|
const Pending = new WeakMap();
|
|
1244
1269
|
const Applied = new WeakMap();
|
|
1245
|
-
function
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
throw Oops$3.NotAllowed(subject, type.name);
|
|
1255
|
-
getPending(subject).push(context => {
|
|
1256
|
-
let instance = context.get(type);
|
|
1257
|
-
if (typeof argument == "function") {
|
|
1258
|
-
if (argument(instance) === false)
|
|
1259
|
-
instance = undefined;
|
|
1270
|
+
function getContextForGetInstruction(type, relativeTo, required) {
|
|
1271
|
+
let item = getParent(type, relativeTo);
|
|
1272
|
+
return (refresh) => {
|
|
1273
|
+
if (item)
|
|
1274
|
+
return item;
|
|
1275
|
+
findRelative(relativeTo, type, got => {
|
|
1276
|
+
if (got) {
|
|
1277
|
+
item = got;
|
|
1278
|
+
refresh(got);
|
|
1260
1279
|
}
|
|
1261
|
-
else if (
|
|
1262
|
-
throw Oops$
|
|
1263
|
-
|
|
1264
|
-
|
|
1280
|
+
else if (required)
|
|
1281
|
+
throw Oops$2.AmbientRequired(type.name, relativeTo);
|
|
1282
|
+
});
|
|
1283
|
+
};
|
|
1284
|
+
}
|
|
1285
|
+
function findRelative(from, type, callback) {
|
|
1286
|
+
if (MVC.isTypeof(type) && type.global)
|
|
1287
|
+
callback(Global$1.get(type));
|
|
1288
|
+
else if (from.constructor.global)
|
|
1289
|
+
throw Oops$2.NotAllowed(from, type.name);
|
|
1290
|
+
else
|
|
1291
|
+
getPending(from).push(context => {
|
|
1292
|
+
callback(context.get(type));
|
|
1265
1293
|
});
|
|
1266
|
-
return {
|
|
1267
|
-
recursive: true,
|
|
1268
|
-
suspend: true
|
|
1269
|
-
};
|
|
1270
|
-
});
|
|
1271
1294
|
}
|
|
1272
1295
|
function usePeerContext(subject) {
|
|
1273
1296
|
if (Applied.has(subject)) {
|
|
@@ -1291,7 +1314,7 @@ function getPending(subject) {
|
|
|
1291
1314
|
return pending;
|
|
1292
1315
|
}
|
|
1293
1316
|
|
|
1294
|
-
function
|
|
1317
|
+
function useModel(source, arg1, arg2) {
|
|
1295
1318
|
const instance = React.useMemo(() => {
|
|
1296
1319
|
const callback = arg2 || arg1;
|
|
1297
1320
|
const instance = Model.isTypeof(source)
|
|
@@ -1304,7 +1327,7 @@ function useNew(source, arg1, arg2) {
|
|
|
1304
1327
|
}, []);
|
|
1305
1328
|
usePeerContext(instance);
|
|
1306
1329
|
if (Array.isArray(arg1)) {
|
|
1307
|
-
const update = useState(0)[1];
|
|
1330
|
+
const update = React.useState(0)[1];
|
|
1308
1331
|
React.useLayoutEffect(() => {
|
|
1309
1332
|
if (arg1.length && instance instanceof Model)
|
|
1310
1333
|
instance.on(arg1, () => update(x => x + 1));
|
|
@@ -1318,19 +1341,10 @@ function useNew(source, arg1, arg2) {
|
|
|
1318
1341
|
const state = React.useState(0);
|
|
1319
1342
|
const local = React.useMemo(() => {
|
|
1320
1343
|
const refresh = state[1].bind(null, x => x + 1);
|
|
1321
|
-
return control(instance)
|
|
1344
|
+
return new Subscriber(control(instance), () => refresh);
|
|
1322
1345
|
}, []);
|
|
1323
|
-
if (typeof arg1 == "object")
|
|
1324
|
-
|
|
1325
|
-
let keys = arg2;
|
|
1326
|
-
local.active = false;
|
|
1327
|
-
if (!keys)
|
|
1328
|
-
keys = getOwnPropertyNames(subject);
|
|
1329
|
-
for (const key of keys)
|
|
1330
|
-
if (key in arg1)
|
|
1331
|
-
subject[key] = arg1[key];
|
|
1332
|
-
waiting.add(() => local.active = true);
|
|
1333
|
-
}
|
|
1346
|
+
if (typeof arg1 == "object")
|
|
1347
|
+
local.apply(arg1, arg2);
|
|
1334
1348
|
React.useLayoutEffect(() => {
|
|
1335
1349
|
local.commit();
|
|
1336
1350
|
return () => {
|
|
@@ -1342,19 +1356,22 @@ function useNew(source, arg1, arg2) {
|
|
|
1342
1356
|
return local.proxy;
|
|
1343
1357
|
}
|
|
1344
1358
|
|
|
1345
|
-
function
|
|
1359
|
+
function useTap(source, arg1, arg2) {
|
|
1360
|
+
const instance = typeof source == "object"
|
|
1361
|
+
? source
|
|
1362
|
+
: "get" in source
|
|
1363
|
+
? source.get()
|
|
1364
|
+
: source();
|
|
1365
|
+
const deps = [uid(instance)];
|
|
1346
1366
|
const state = React.useState(0);
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
const deps = [uid(source)];
|
|
1354
|
-
const local = use(refresh => {
|
|
1355
|
-
const sub = control(source).subscribe(() => update);
|
|
1367
|
+
const local = React.useMemo(() => {
|
|
1368
|
+
const refresh = state[1].bind(null, x => x + 1);
|
|
1369
|
+
const controller = control(instance);
|
|
1370
|
+
if (typeof arg1 != "function")
|
|
1371
|
+
return new Subscriber(controller, () => refresh, arg1);
|
|
1372
|
+
const sub = new Subscriber(controller, () => update);
|
|
1356
1373
|
const spy = sub.proxy;
|
|
1357
|
-
let make = () =>
|
|
1374
|
+
let make = () => arg1.call(spy, spy, forceUpdate);
|
|
1358
1375
|
function forceUpdate(passthru) {
|
|
1359
1376
|
if (typeof passthru == "function")
|
|
1360
1377
|
passthru = passthru();
|
|
@@ -1385,7 +1402,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1385
1402
|
if (typeof value == "function") {
|
|
1386
1403
|
const get = value;
|
|
1387
1404
|
sub.watch.clear();
|
|
1388
|
-
|
|
1405
|
+
arg1 = () => get();
|
|
1389
1406
|
value = get();
|
|
1390
1407
|
}
|
|
1391
1408
|
if (value instanceof Promise) {
|
|
@@ -1396,7 +1413,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1396
1413
|
sub.commit();
|
|
1397
1414
|
update = () => {
|
|
1398
1415
|
const next = make();
|
|
1399
|
-
if (value
|
|
1416
|
+
if (notEqual(value, next))
|
|
1400
1417
|
reassign(next);
|
|
1401
1418
|
};
|
|
1402
1419
|
}
|
|
@@ -1404,7 +1421,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1404
1421
|
get() {
|
|
1405
1422
|
if (value !== undefined)
|
|
1406
1423
|
return value;
|
|
1407
|
-
if (
|
|
1424
|
+
if (arg2)
|
|
1408
1425
|
throw new Promise(res => retry = res);
|
|
1409
1426
|
return null;
|
|
1410
1427
|
}
|
|
@@ -1413,67 +1430,47 @@ function useCompute(source, compute, suspend) {
|
|
|
1413
1430
|
}, deps);
|
|
1414
1431
|
if (!local)
|
|
1415
1432
|
return null;
|
|
1416
|
-
React.useLayoutEffect(() =>
|
|
1433
|
+
React.useLayoutEffect(() => {
|
|
1434
|
+
local.commit();
|
|
1435
|
+
return () => local.release();
|
|
1436
|
+
}, deps);
|
|
1417
1437
|
return local.proxy;
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
function useTap(source, arg1, arg2) {
|
|
1421
|
-
const instance = typeof source == "object"
|
|
1422
|
-
? source
|
|
1423
|
-
: "get" in source
|
|
1424
|
-
? source.get()
|
|
1425
|
-
: useContext(source);
|
|
1426
|
-
return typeof arg1 == "function"
|
|
1427
|
-
? useCompute(instance, arg1, arg2)
|
|
1428
|
-
: useSubscribe(instance, arg1, arg2);
|
|
1429
1438
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
return local.proxy;
|
|
1436
|
-
const value = local.proxy[path];
|
|
1437
|
-
if (value === undefined && expect)
|
|
1438
|
-
throw suspend(local.parent, path);
|
|
1439
|
-
return value;
|
|
1440
|
-
}
|
|
1439
|
+
/** Values are not equal for purposes of a refresh. */
|
|
1440
|
+
const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
|
|
1441
|
+
!Array.isArray(b) ||
|
|
1442
|
+
a.length !== b.length ||
|
|
1443
|
+
a.some((x, i) => x !== b[i])));
|
|
1441
1444
|
|
|
1442
|
-
const Global$1 = new WeakMap();
|
|
1443
|
-
const Oops$2 = issues({
|
|
1444
|
-
DoesNotExist: (name) => `Tried to access singleton ${name}, but none exist! Did you forget to initialize?\nCall ${name}.new() before attempting to access, or consider using ${name}.use() instead.`,
|
|
1445
|
-
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1446
|
-
});
|
|
1447
1445
|
class MVC extends Model {
|
|
1448
1446
|
end(force) {
|
|
1449
1447
|
const type = this.constructor;
|
|
1450
1448
|
if (type.keepAlive && !force)
|
|
1451
1449
|
return false;
|
|
1452
1450
|
super.end();
|
|
1453
|
-
Global$1.delete(
|
|
1451
|
+
Global$1.delete(this);
|
|
1454
1452
|
return true;
|
|
1455
1453
|
}
|
|
1456
1454
|
static new(...args) {
|
|
1457
|
-
|
|
1455
|
+
const exists = Global$1.get(this);
|
|
1456
|
+
if (exists)
|
|
1458
1457
|
if (this.keepAlive)
|
|
1459
|
-
return
|
|
1458
|
+
return exists;
|
|
1460
1459
|
else
|
|
1461
|
-
throw Oops$
|
|
1460
|
+
throw Oops$3.AlreadyExists(this.name);
|
|
1462
1461
|
const instance = super.new(...args);
|
|
1463
1462
|
if (this.global)
|
|
1464
|
-
Global$1.
|
|
1463
|
+
Global$1.add(instance);
|
|
1465
1464
|
return instance;
|
|
1466
1465
|
}
|
|
1467
1466
|
static get(arg1, arg2) {
|
|
1468
|
-
let instance;
|
|
1469
1467
|
const required = arg1 === undefined || arg1 === true;
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
instance = useContext(this, required);
|
|
1468
|
+
const instance = useContext(this, required);
|
|
1469
|
+
if (typeof arg1 === "function" && instance)
|
|
1470
|
+
callback(arg1);
|
|
1471
|
+
else if (arg2)
|
|
1472
|
+
callback(arg2);
|
|
1473
|
+
return instance;
|
|
1477
1474
|
function callback(effect) {
|
|
1478
1475
|
try {
|
|
1479
1476
|
React.useLayoutEffect(() => effect(instance), []);
|
|
@@ -1485,29 +1482,18 @@ class MVC extends Model {
|
|
|
1485
1482
|
effect(undefined);
|
|
1486
1483
|
}
|
|
1487
1484
|
}
|
|
1488
|
-
if (typeof arg1 === "string")
|
|
1489
|
-
return instance[arg1];
|
|
1490
|
-
if (typeof arg1 === "function" && instance)
|
|
1491
|
-
callback(arg1);
|
|
1492
|
-
else if (arg2)
|
|
1493
|
-
callback(arg2);
|
|
1494
|
-
return instance;
|
|
1495
1485
|
}
|
|
1496
1486
|
static tap(arg1, arg2) {
|
|
1497
|
-
|
|
1498
|
-
return typeof arg1 == "function"
|
|
1499
|
-
? useCompute(instance, arg1, arg2)
|
|
1500
|
-
: useSubscribe(instance, arg1, arg2);
|
|
1487
|
+
return useTap(this, arg1, arg2);
|
|
1501
1488
|
}
|
|
1502
1489
|
static use(a, b) {
|
|
1503
|
-
return
|
|
1490
|
+
return useModel(this, a, b);
|
|
1504
1491
|
}
|
|
1505
1492
|
static meta(arg1, arg2) {
|
|
1506
|
-
return
|
|
1507
|
-
? useCompute(this, arg1, arg2)
|
|
1508
|
-
: useSubscribe(this, arg1, arg2);
|
|
1493
|
+
return useTap(() => this, arg1, arg2);
|
|
1509
1494
|
}
|
|
1510
|
-
}
|
|
1495
|
+
}
|
|
1496
|
+
FindInstruction.set(MVC, getContextForGetInstruction);
|
|
1511
1497
|
|
|
1512
1498
|
const Oops$1 = issues({
|
|
1513
1499
|
BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
@@ -1541,8 +1527,17 @@ function useNewContext(include, assign) {
|
|
|
1541
1527
|
throw Oops.NoType();
|
|
1542
1528
|
return ambient.push();
|
|
1543
1529
|
}, []);
|
|
1544
|
-
function register(key,
|
|
1545
|
-
|
|
1530
|
+
function register(key, input) {
|
|
1531
|
+
let instance;
|
|
1532
|
+
if (MVC.isTypeof(input) && input.global)
|
|
1533
|
+
instance = input.new();
|
|
1534
|
+
else if (context.register.get(key) === input)
|
|
1535
|
+
instance = typeof input == "object"
|
|
1536
|
+
? input
|
|
1537
|
+
: context.get(input);
|
|
1538
|
+
else
|
|
1539
|
+
instance = context.add(input, key);
|
|
1540
|
+
init.add(instance);
|
|
1546
1541
|
if (assign)
|
|
1547
1542
|
assignWeak(instance, assign);
|
|
1548
1543
|
}
|
|
@@ -1605,4 +1600,4 @@ const Debug = {
|
|
|
1605
1600
|
UPDATE
|
|
1606
1601
|
};
|
|
1607
1602
|
|
|
1608
|
-
export { Consumer, Debug, Global, MVC, MVC as Model, Provider, add, MVC as default, get,
|
|
1603
|
+
export { Consumer, Debug, Global, MVC, MVC as Model, Provider, add, MVC as default, get, ref, run, set, use };
|