@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.js
CHANGED
|
@@ -8,6 +8,23 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
8
8
|
|
|
9
9
|
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
10
10
|
|
|
11
|
+
class Issue extends Error {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
// drop first line (error factory) in stack trace.
|
|
15
|
+
this.stack = this.stack.replace(/\n.+/, "");
|
|
16
|
+
}
|
|
17
|
+
warn() {
|
|
18
|
+
console.warn(this.message);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function issues(register) {
|
|
22
|
+
const Library = {};
|
|
23
|
+
for (const name in register)
|
|
24
|
+
Library[name] = (...args) => new Issue(register[name].apply(null, args));
|
|
25
|
+
return Library;
|
|
26
|
+
}
|
|
27
|
+
|
|
11
28
|
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
12
29
|
const UID_CACHE = new WeakMap();
|
|
13
30
|
function assignWeak(into, from) {
|
|
@@ -22,28 +39,82 @@ function uid(object) {
|
|
|
22
39
|
return uid;
|
|
23
40
|
}
|
|
24
41
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
this.
|
|
42
|
+
const REGISTER$1 = new WeakMap();
|
|
43
|
+
class Subscriber {
|
|
44
|
+
constructor(parent, onUpdate, strict) {
|
|
45
|
+
this.parent = parent;
|
|
46
|
+
this.onUpdate = onUpdate;
|
|
47
|
+
this.strict = strict;
|
|
48
|
+
this.active = false;
|
|
49
|
+
this.dependant = new Set();
|
|
50
|
+
this.watch = new Map();
|
|
51
|
+
const proxy = create(parent.subject);
|
|
52
|
+
const reset = () => this.latest = undefined;
|
|
53
|
+
REGISTER$1.set(proxy, this);
|
|
54
|
+
defineProperty(this, "proxy", {
|
|
55
|
+
configurable: true,
|
|
56
|
+
get() {
|
|
57
|
+
setTimeout(reset, 0);
|
|
58
|
+
return proxy;
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
this.clear = parent.addListener(key => {
|
|
62
|
+
if (this.active)
|
|
63
|
+
this.notify(key);
|
|
64
|
+
});
|
|
30
65
|
}
|
|
31
|
-
|
|
32
|
-
|
|
66
|
+
get using() {
|
|
67
|
+
return Array.from(this.watch.keys());
|
|
68
|
+
}
|
|
69
|
+
apply(values, keys) {
|
|
70
|
+
const { waiting, subject } = this.parent;
|
|
71
|
+
this.active = false;
|
|
72
|
+
if (!keys)
|
|
73
|
+
keys = getOwnPropertyNames(subject);
|
|
74
|
+
for (const key of keys)
|
|
75
|
+
if (key in values)
|
|
76
|
+
subject[key] = values[key];
|
|
77
|
+
waiting.add(() => this.active = true);
|
|
78
|
+
}
|
|
79
|
+
follow(key, value) {
|
|
80
|
+
if (value !== undefined)
|
|
81
|
+
this.watch.set(key, value);
|
|
82
|
+
else if (!this.watch.has(key))
|
|
83
|
+
this.watch.set(key, true);
|
|
84
|
+
}
|
|
85
|
+
commit() {
|
|
86
|
+
this.active = true;
|
|
87
|
+
this.dependant.forEach(x => x.commit());
|
|
88
|
+
}
|
|
89
|
+
release() {
|
|
90
|
+
this.clear();
|
|
91
|
+
this.dependant.forEach(x => x.release());
|
|
92
|
+
}
|
|
93
|
+
notify(key) {
|
|
94
|
+
const { parent, watch } = this;
|
|
95
|
+
const handler = watch.get(key);
|
|
96
|
+
if (!handler)
|
|
97
|
+
return;
|
|
98
|
+
if (typeof handler == "function")
|
|
99
|
+
handler();
|
|
100
|
+
const notify = this.onUpdate(key, parent);
|
|
101
|
+
if (notify) {
|
|
102
|
+
parent.waiting.add(update => {
|
|
103
|
+
this.latest = update.filter(k => watch.has(k));
|
|
104
|
+
});
|
|
105
|
+
parent.waiting.add(notify);
|
|
106
|
+
}
|
|
33
107
|
}
|
|
34
108
|
}
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
for (const name in register)
|
|
38
|
-
Library[name] = (...args) => new Issue(register[name].apply(null, args));
|
|
39
|
-
return Library;
|
|
109
|
+
function subscriber(from) {
|
|
110
|
+
return REGISTER$1.get(from);
|
|
40
111
|
}
|
|
41
112
|
|
|
42
|
-
const Oops$
|
|
113
|
+
const Oops$c = issues({
|
|
43
114
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
44
115
|
});
|
|
45
116
|
function suspend(source, key) {
|
|
46
|
-
const error = Oops$
|
|
117
|
+
const error = Oops$c.NotReady(source.subject, key);
|
|
47
118
|
const promise = new Promise(resolve => {
|
|
48
119
|
const release = source.addListener(forKey => {
|
|
49
120
|
if (forKey == key)
|
|
@@ -83,98 +154,87 @@ function mayRetry(fn) {
|
|
|
83
154
|
return compute();
|
|
84
155
|
}
|
|
85
156
|
|
|
86
|
-
const
|
|
87
|
-
|
|
157
|
+
const Parent = new WeakMap();
|
|
158
|
+
const Oops$b = issues({
|
|
159
|
+
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`,
|
|
160
|
+
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
161
|
+
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
88
162
|
});
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
let pending = KEYS.get(self);
|
|
97
|
-
if (!order)
|
|
98
|
-
ORDER.set(self, order = new Map());
|
|
99
|
-
if (!pending)
|
|
100
|
-
KEYS.set(self, pending = new Set());
|
|
101
|
-
const compute = (initial) => {
|
|
102
|
-
try {
|
|
103
|
-
return setter.call(sub.proxy, sub.proxy);
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
Oops$e.Failed(subject, key, initial).warn();
|
|
107
|
-
throw err;
|
|
108
|
-
}
|
|
163
|
+
function getParentForGetInstruction(type, relativeTo, required) {
|
|
164
|
+
const item = getParent(type, relativeTo);
|
|
165
|
+
return (_refresh) => {
|
|
166
|
+
if (item)
|
|
167
|
+
return item;
|
|
168
|
+
if (required)
|
|
169
|
+
throw Oops$b.Required(type.name, relativeTo);
|
|
109
170
|
};
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
171
|
+
}
|
|
172
|
+
function getParent(type, from) {
|
|
173
|
+
const value = Parent.get(from);
|
|
174
|
+
if (value && !(value instanceof type))
|
|
175
|
+
throw Oops$b.Unexpected(type.name, from, value);
|
|
176
|
+
return value;
|
|
177
|
+
}
|
|
178
|
+
function getRecursive(key, from) {
|
|
179
|
+
const context = new WeakMap();
|
|
180
|
+
const { state } = from;
|
|
181
|
+
return (local) => {
|
|
182
|
+
if (!state.has(key))
|
|
183
|
+
throw suspend(from, key);
|
|
184
|
+
if (!local)
|
|
185
|
+
return state.get(key);
|
|
186
|
+
if (!context.has(local)) {
|
|
187
|
+
let reset;
|
|
188
|
+
const init = () => {
|
|
189
|
+
if (reset)
|
|
190
|
+
reset();
|
|
191
|
+
const value = state.get(key);
|
|
192
|
+
if (value && controller(value)) {
|
|
193
|
+
const child = new Subscriber(control(value), local.onUpdate);
|
|
194
|
+
if (local.active)
|
|
195
|
+
child.commit();
|
|
196
|
+
local.dependant.add(child);
|
|
197
|
+
context.set(local, child.proxy);
|
|
198
|
+
reset = () => {
|
|
199
|
+
child.release();
|
|
200
|
+
local.dependant.delete(child);
|
|
201
|
+
context.set(local, undefined);
|
|
202
|
+
reset = undefined;
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
local.follow(key, init);
|
|
207
|
+
init();
|
|
124
208
|
}
|
|
209
|
+
return context.get(local);
|
|
125
210
|
};
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
catch (e) {
|
|
140
|
-
throw e;
|
|
141
|
-
}
|
|
142
|
-
finally {
|
|
143
|
-
sub.commit();
|
|
144
|
-
order.set(refresh, order.size);
|
|
145
|
-
}
|
|
211
|
+
}
|
|
212
|
+
function setRecursive(controller, key, initial) {
|
|
213
|
+
const { state, subject } = controller;
|
|
214
|
+
const Type = initial.constructor;
|
|
215
|
+
let get;
|
|
216
|
+
const onUpdate = (next) => {
|
|
217
|
+
state.set(key, next);
|
|
218
|
+
if (!(next instanceof Type))
|
|
219
|
+
throw Oops$b.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
220
|
+
get = getRecursive(key, controller);
|
|
221
|
+
Parent.set(next, subject);
|
|
222
|
+
control(next);
|
|
223
|
+
return true;
|
|
146
224
|
};
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
225
|
+
onUpdate(initial);
|
|
226
|
+
defineProperty(subject, key, {
|
|
227
|
+
set: controller.ref(key, onUpdate),
|
|
228
|
+
get() {
|
|
229
|
+
const local = subscriber(this);
|
|
230
|
+
if (local)
|
|
231
|
+
local.follow(key);
|
|
232
|
+
return get(local);
|
|
152
233
|
}
|
|
153
|
-
|
|
154
|
-
if (value === undefined && required)
|
|
155
|
-
throw suspend(self, key);
|
|
156
|
-
return value;
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function flush(control) {
|
|
160
|
-
const pending = KEYS.get(control);
|
|
161
|
-
if (!pending || !pending.size)
|
|
162
|
-
return;
|
|
163
|
-
const priority = ORDER.get(control);
|
|
164
|
-
while (pending.size) {
|
|
165
|
-
let compute;
|
|
166
|
-
for (const item of pending)
|
|
167
|
-
if (!compute || priority.get(item) < priority.get(compute))
|
|
168
|
-
compute = item;
|
|
169
|
-
pending.delete(compute);
|
|
170
|
-
const key = INFO.get(compute);
|
|
171
|
-
if (!control.frame.has(key))
|
|
172
|
-
compute();
|
|
173
|
-
}
|
|
174
|
-
pending.clear();
|
|
234
|
+
});
|
|
175
235
|
}
|
|
176
236
|
|
|
177
|
-
const Oops$
|
|
237
|
+
const Oops$a = issues({
|
|
178
238
|
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
179
239
|
});
|
|
180
240
|
function createEffect(model, callback, keys) {
|
|
@@ -188,7 +248,7 @@ function createEffect(model, callback, keys) {
|
|
|
188
248
|
if (unSet instanceof Promise)
|
|
189
249
|
unSet = undefined;
|
|
190
250
|
if (unSet && typeof unSet !== "function")
|
|
191
|
-
throw Oops$
|
|
251
|
+
throw Oops$a.BadCallback();
|
|
192
252
|
}
|
|
193
253
|
function invoke() {
|
|
194
254
|
if (busy)
|
|
@@ -212,10 +272,11 @@ function createEffect(model, callback, keys) {
|
|
|
212
272
|
return invoke;
|
|
213
273
|
});
|
|
214
274
|
}
|
|
215
|
-
const sub = controller
|
|
275
|
+
const sub = new Subscriber(controller, () => invoke);
|
|
216
276
|
model = sub.proxy;
|
|
217
277
|
invoke();
|
|
218
|
-
|
|
278
|
+
sub.commit();
|
|
279
|
+
return () => sub.release();
|
|
219
280
|
});
|
|
220
281
|
}
|
|
221
282
|
function createValueEffect(callback) {
|
|
@@ -231,11 +292,11 @@ function createValueEffect(callback) {
|
|
|
231
292
|
if (typeof out == "function")
|
|
232
293
|
unSet = out;
|
|
233
294
|
else
|
|
234
|
-
throw Oops$
|
|
295
|
+
throw Oops$a.BadCallback();
|
|
235
296
|
};
|
|
236
297
|
}
|
|
237
298
|
|
|
238
|
-
const Oops$
|
|
299
|
+
const Oops$9 = issues({
|
|
239
300
|
Timeout: (keys, timeout) => `No update seen for [${keys}] within ${timeout}.`,
|
|
240
301
|
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
241
302
|
StrictUpdate: () => `Expected update but none in progress.`,
|
|
@@ -271,13 +332,13 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
271
332
|
const timeout = (message) => {
|
|
272
333
|
const k = keys ? keys.join(", ") : "any";
|
|
273
334
|
removeListener();
|
|
274
|
-
reject(Oops$
|
|
335
|
+
reject(Oops$9.Timeout(k, message));
|
|
275
336
|
};
|
|
276
337
|
const removeListener = control(source, controller => {
|
|
277
338
|
const pending = controller.frame;
|
|
278
339
|
if (keys === null) {
|
|
279
340
|
if (pending.size)
|
|
280
|
-
reject(Oops$
|
|
341
|
+
reject(Oops$9.StrictNoUpdate());
|
|
281
342
|
else
|
|
282
343
|
resolve(null);
|
|
283
344
|
return;
|
|
@@ -285,7 +346,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
285
346
|
if (keys) {
|
|
286
347
|
if (keys.length) {
|
|
287
348
|
if (arg2 === 0 && single && !pending.has(keys[0])) {
|
|
288
|
-
reject(Oops$
|
|
349
|
+
reject(Oops$9.KeysExpected(keys[0]));
|
|
289
350
|
return;
|
|
290
351
|
}
|
|
291
352
|
else
|
|
@@ -297,7 +358,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
297
358
|
}
|
|
298
359
|
}
|
|
299
360
|
else if (!pending.size && arg1 === true || arg2 === 0) {
|
|
300
|
-
reject(Oops$
|
|
361
|
+
reject(Oops$9.StrictUpdate());
|
|
301
362
|
return;
|
|
302
363
|
}
|
|
303
364
|
else
|
|
@@ -320,67 +381,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
320
381
|
});
|
|
321
382
|
}
|
|
322
383
|
|
|
323
|
-
const
|
|
324
|
-
class Subscriber {
|
|
325
|
-
constructor(parent, onUpdate) {
|
|
326
|
-
this.parent = parent;
|
|
327
|
-
this.onUpdate = onUpdate;
|
|
328
|
-
this.active = false;
|
|
329
|
-
this.dependant = new Set();
|
|
330
|
-
this.watch = new Map();
|
|
331
|
-
const proxy = create(parent.subject);
|
|
332
|
-
const reset = () => this.latest = undefined;
|
|
333
|
-
REGISTER$1.set(proxy, this);
|
|
334
|
-
defineProperty(this, "proxy", {
|
|
335
|
-
configurable: true,
|
|
336
|
-
get() {
|
|
337
|
-
setTimeout(reset, 0);
|
|
338
|
-
return proxy;
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
get using() {
|
|
343
|
-
return Array.from(this.watch.keys());
|
|
344
|
-
}
|
|
345
|
-
add(key, value) {
|
|
346
|
-
if (value !== undefined)
|
|
347
|
-
this.watch.set(key, value);
|
|
348
|
-
else if (!this.watch.has(key))
|
|
349
|
-
this.watch.set(key, true);
|
|
350
|
-
}
|
|
351
|
-
commit() {
|
|
352
|
-
const release = this.parent.addListener(key => {
|
|
353
|
-
if (this.active)
|
|
354
|
-
this.onEvent(key);
|
|
355
|
-
});
|
|
356
|
-
this.active = true;
|
|
357
|
-
this.dependant.forEach(x => x.commit());
|
|
358
|
-
return this.release = () => {
|
|
359
|
-
this.dependant.forEach(x => x.release());
|
|
360
|
-
release();
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
onEvent(key) {
|
|
364
|
-
const { parent, watch } = this;
|
|
365
|
-
let handler = watch.get(key);
|
|
366
|
-
if (typeof handler == "function")
|
|
367
|
-
handler = handler();
|
|
368
|
-
if (handler) {
|
|
369
|
-
const notify = this.onUpdate(key, parent);
|
|
370
|
-
if (notify) {
|
|
371
|
-
parent.waiting.add(update => {
|
|
372
|
-
this.latest = update.filter(k => watch.has(k));
|
|
373
|
-
});
|
|
374
|
-
parent.waiting.add(notify);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function subscriber(from) {
|
|
380
|
-
return REGISTER$1.get(from);
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
const Oops$b = issues({
|
|
384
|
+
const Oops$8 = issues({
|
|
384
385
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
385
386
|
});
|
|
386
387
|
class Model {
|
|
@@ -438,7 +439,7 @@ class Model {
|
|
|
438
439
|
return {
|
|
439
440
|
then: (callback) => {
|
|
440
441
|
if (!callback)
|
|
441
|
-
throw Oops$
|
|
442
|
+
throw Oops$8.NoChaining();
|
|
442
443
|
controller.waiting.add(callback);
|
|
443
444
|
}
|
|
444
445
|
};
|
|
@@ -471,11 +472,150 @@ class Model {
|
|
|
471
472
|
maybe.prototype instanceof this);
|
|
472
473
|
}
|
|
473
474
|
}
|
|
474
|
-
defineProperty(Model.prototype, "toString", {
|
|
475
|
-
value() {
|
|
476
|
-
return this.constructor.name;
|
|
477
|
-
}
|
|
478
|
-
});
|
|
475
|
+
defineProperty(Model.prototype, "toString", {
|
|
476
|
+
value() {
|
|
477
|
+
return this.constructor.name;
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
const FindInstruction = new WeakMap([
|
|
481
|
+
[Model, getParentForGetInstruction]
|
|
482
|
+
]);
|
|
483
|
+
|
|
484
|
+
const Oops$7 = issues({
|
|
485
|
+
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
486
|
+
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
487
|
+
});
|
|
488
|
+
function get(arg0, arg1) {
|
|
489
|
+
return add(function get(key) {
|
|
490
|
+
const { subject, state } = this;
|
|
491
|
+
// Easy mistake, using a peer, will always be unresolved.
|
|
492
|
+
if (typeof arg0 == "symbol")
|
|
493
|
+
throw Oops$7.PeerNotAllowed(subject, key);
|
|
494
|
+
let source;
|
|
495
|
+
const sourceRequired = arg1 !== false;
|
|
496
|
+
if (arg0 instanceof Model) {
|
|
497
|
+
source = () => arg0;
|
|
498
|
+
if (typeof arg1 !== "function")
|
|
499
|
+
throw new Error(`Factory argument cannot be ${arg1}`);
|
|
500
|
+
}
|
|
501
|
+
else if (Model.isTypeof(arg0)) {
|
|
502
|
+
source = find(arg0, subject, sourceRequired);
|
|
503
|
+
}
|
|
504
|
+
else if (typeof arg0 == "function") {
|
|
505
|
+
arg1 = arg0.call(subject, key, subject);
|
|
506
|
+
source = () => subject;
|
|
507
|
+
}
|
|
508
|
+
if (typeof arg1 == "function")
|
|
509
|
+
return getComputed(key, this, source, arg1);
|
|
510
|
+
else {
|
|
511
|
+
const init = source((got) => {
|
|
512
|
+
state.set(key, got);
|
|
513
|
+
this.update(key);
|
|
514
|
+
});
|
|
515
|
+
// TODO: remove fixes suspense test
|
|
516
|
+
if (init || arg1 === false)
|
|
517
|
+
state.set(key, init);
|
|
518
|
+
return getRecursive(key, this);
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
function getComputed(key, parent, source, setter) {
|
|
523
|
+
const { state } = parent;
|
|
524
|
+
let sub;
|
|
525
|
+
let order = ORDER.get(parent);
|
|
526
|
+
let pending = KEYS.get(parent);
|
|
527
|
+
let instance;
|
|
528
|
+
if (!order)
|
|
529
|
+
ORDER.set(parent, order = new Map());
|
|
530
|
+
if (!pending)
|
|
531
|
+
KEYS.set(parent, pending = new Set());
|
|
532
|
+
const compute = (initial) => {
|
|
533
|
+
try {
|
|
534
|
+
return setter.call(sub.proxy, sub.proxy);
|
|
535
|
+
}
|
|
536
|
+
catch (err) {
|
|
537
|
+
Oops$7.Failed(instance, key, initial).warn();
|
|
538
|
+
throw err;
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
const create = () => {
|
|
542
|
+
// TODO: replace create with a cleanup function
|
|
543
|
+
const got = source(create);
|
|
544
|
+
if (!got)
|
|
545
|
+
throw suspend(parent, key);
|
|
546
|
+
instance = got;
|
|
547
|
+
sub = new Subscriber(control(instance), (_, control) => {
|
|
548
|
+
if (control !== parent)
|
|
549
|
+
refresh();
|
|
550
|
+
else
|
|
551
|
+
pending.add(refresh);
|
|
552
|
+
});
|
|
553
|
+
sub.watch.set(key, false);
|
|
554
|
+
try {
|
|
555
|
+
const value = compute(true);
|
|
556
|
+
state.set(key, value);
|
|
557
|
+
return value;
|
|
558
|
+
}
|
|
559
|
+
finally {
|
|
560
|
+
sub.commit();
|
|
561
|
+
order.set(refresh, order.size);
|
|
562
|
+
}
|
|
563
|
+
};
|
|
564
|
+
const refresh = () => {
|
|
565
|
+
let value;
|
|
566
|
+
try {
|
|
567
|
+
value = compute(false);
|
|
568
|
+
}
|
|
569
|
+
catch (e) {
|
|
570
|
+
console.error(e);
|
|
571
|
+
}
|
|
572
|
+
finally {
|
|
573
|
+
if (state.get(key) !== value) {
|
|
574
|
+
state.set(key, value);
|
|
575
|
+
parent.update(key);
|
|
576
|
+
return value;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
};
|
|
580
|
+
INFO.set(refresh, key);
|
|
581
|
+
return () => {
|
|
582
|
+
if (pending.has(refresh)) {
|
|
583
|
+
pending.delete(refresh);
|
|
584
|
+
refresh();
|
|
585
|
+
}
|
|
586
|
+
return sub ? state.get(key) : create();
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
const INFO = new WeakMap();
|
|
590
|
+
const KEYS = new WeakMap();
|
|
591
|
+
const ORDER = new WeakMap();
|
|
592
|
+
function flush(control) {
|
|
593
|
+
const pending = KEYS.get(control);
|
|
594
|
+
if (!pending || !pending.size)
|
|
595
|
+
return;
|
|
596
|
+
const priority = ORDER.get(control);
|
|
597
|
+
while (pending.size) {
|
|
598
|
+
let compute;
|
|
599
|
+
for (const item of pending)
|
|
600
|
+
if (!compute || priority.get(item) < priority.get(compute))
|
|
601
|
+
compute = item;
|
|
602
|
+
pending.delete(compute);
|
|
603
|
+
const key = INFO.get(compute);
|
|
604
|
+
if (!control.frame.has(key))
|
|
605
|
+
compute();
|
|
606
|
+
}
|
|
607
|
+
pending.clear();
|
|
608
|
+
}
|
|
609
|
+
// TODO: collapse this function when MVC is merged into Model.
|
|
610
|
+
function find(type, relativeTo, required) {
|
|
611
|
+
let T = type;
|
|
612
|
+
do {
|
|
613
|
+
T = getPrototypeOf(T);
|
|
614
|
+
const getter = FindInstruction.get(T);
|
|
615
|
+
if (getter)
|
|
616
|
+
return getter(type, relativeTo, required);
|
|
617
|
+
} while (T.prototype instanceof Model);
|
|
618
|
+
}
|
|
479
619
|
|
|
480
620
|
const REGISTER = new WeakMap();
|
|
481
621
|
const PENDING = new Map();
|
|
@@ -487,9 +627,6 @@ class Control {
|
|
|
487
627
|
this.followers = new Set();
|
|
488
628
|
REGISTER.set(subject, this);
|
|
489
629
|
}
|
|
490
|
-
subscribe(callback) {
|
|
491
|
-
return new Subscriber(this, callback);
|
|
492
|
-
}
|
|
493
630
|
watch(key) {
|
|
494
631
|
const { subject, state } = this;
|
|
495
632
|
const { value } = getOwnPropertyDescriptor(subject, key);
|
|
@@ -500,7 +637,7 @@ class Control {
|
|
|
500
637
|
if (instruction) {
|
|
501
638
|
delete subject[key];
|
|
502
639
|
PENDING.delete(value);
|
|
503
|
-
instruction
|
|
640
|
+
instruction(this, key);
|
|
504
641
|
}
|
|
505
642
|
return;
|
|
506
643
|
}
|
|
@@ -514,9 +651,13 @@ class Control {
|
|
|
514
651
|
set: this.ref(key),
|
|
515
652
|
get() {
|
|
516
653
|
const sub = subscriber(this);
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
654
|
+
const value = state.get(key);
|
|
655
|
+
if (sub) {
|
|
656
|
+
sub.follow(key);
|
|
657
|
+
if (value === undefined && sub.strict)
|
|
658
|
+
throw suspend(this, key);
|
|
659
|
+
}
|
|
660
|
+
return value;
|
|
520
661
|
}
|
|
521
662
|
});
|
|
522
663
|
}
|
|
@@ -574,6 +715,8 @@ class Control {
|
|
|
574
715
|
listeners.forEach(x => x(null, this));
|
|
575
716
|
}
|
|
576
717
|
}
|
|
718
|
+
Control.get = controller;
|
|
719
|
+
Control.for = control;
|
|
577
720
|
function controller(from) {
|
|
578
721
|
if ("is" in from)
|
|
579
722
|
from = from.is;
|
|
@@ -603,68 +746,6 @@ function control(subject, cb) {
|
|
|
603
746
|
return cb ? cb(control) : control;
|
|
604
747
|
}
|
|
605
748
|
|
|
606
|
-
const Parent = new WeakMap();
|
|
607
|
-
const Oops$a = issues({
|
|
608
|
-
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
|
|
609
|
-
});
|
|
610
|
-
function getRecursive(key, from) {
|
|
611
|
-
const context = new WeakMap();
|
|
612
|
-
const { state } = from;
|
|
613
|
-
return (local) => {
|
|
614
|
-
if (!local)
|
|
615
|
-
return state.get(key);
|
|
616
|
-
if (!context.has(local)) {
|
|
617
|
-
let reset;
|
|
618
|
-
const init = () => {
|
|
619
|
-
if (reset)
|
|
620
|
-
reset();
|
|
621
|
-
const value = state.get(key);
|
|
622
|
-
if (value && controller(value)) {
|
|
623
|
-
const child = control(value).subscribe(local.onUpdate);
|
|
624
|
-
if (local.active)
|
|
625
|
-
child.commit();
|
|
626
|
-
local.dependant.add(child);
|
|
627
|
-
context.set(local, child.proxy);
|
|
628
|
-
reset = () => {
|
|
629
|
-
child.release();
|
|
630
|
-
local.dependant.delete(child);
|
|
631
|
-
context.set(local, undefined);
|
|
632
|
-
reset = undefined;
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
return true;
|
|
636
|
-
};
|
|
637
|
-
local.add(key, init);
|
|
638
|
-
init();
|
|
639
|
-
}
|
|
640
|
-
return context.get(local);
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
function setRecursive(controller, key, initial) {
|
|
644
|
-
const { state, subject } = controller;
|
|
645
|
-
const Type = initial.constructor;
|
|
646
|
-
let get;
|
|
647
|
-
const onUpdate = (next) => {
|
|
648
|
-
state.set(key, next);
|
|
649
|
-
if (!(next instanceof Type))
|
|
650
|
-
throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
651
|
-
get = getRecursive(key, controller);
|
|
652
|
-
Parent.set(next, subject);
|
|
653
|
-
control(next);
|
|
654
|
-
return true;
|
|
655
|
-
};
|
|
656
|
-
onUpdate(initial);
|
|
657
|
-
defineProperty(subject, key, {
|
|
658
|
-
set: controller.ref(key, onUpdate),
|
|
659
|
-
get() {
|
|
660
|
-
const local = subscriber(this);
|
|
661
|
-
if (local)
|
|
662
|
-
local.add(key);
|
|
663
|
-
return get(local);
|
|
664
|
-
}
|
|
665
|
-
});
|
|
666
|
-
}
|
|
667
|
-
|
|
668
749
|
/**
|
|
669
750
|
* Run instruction as controller sets itself up.
|
|
670
751
|
* This will specialize the behavior of a given property.
|
|
@@ -672,53 +753,42 @@ function setRecursive(controller, key, initial) {
|
|
|
672
753
|
function add(instruction, label) {
|
|
673
754
|
const name = label || instruction.name || "pending";
|
|
674
755
|
const placeholder = Symbol(`${name} instruction`);
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
756
|
+
PENDING.set(placeholder, (control, key) => {
|
|
757
|
+
let output = instruction.call(control, key, control);
|
|
758
|
+
if (!output)
|
|
759
|
+
return undefined;
|
|
678
760
|
if (typeof output == "function")
|
|
679
761
|
output = { get: output };
|
|
680
|
-
if (typeof output != "object")
|
|
681
|
-
return;
|
|
682
|
-
if ("explicit" in output && output.explicit) {
|
|
683
|
-
defineProperty(subject, key, output);
|
|
684
|
-
return false;
|
|
685
|
-
}
|
|
686
|
-
let { get: onGet, set: onSet, suspend: shouldSuspend } = output;
|
|
687
762
|
if ("value" in output)
|
|
688
|
-
state.set(key, output.value);
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
if (destroy)
|
|
694
|
-
this.addListener((key) => {
|
|
695
|
-
if (key == null)
|
|
696
|
-
destroy();
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
const control = this;
|
|
700
|
-
defineProperty(subject, key, {
|
|
701
|
-
enumerable: output.enumerable,
|
|
702
|
-
set: onSet === false
|
|
763
|
+
control.state.set(key, output.value);
|
|
764
|
+
let { enumerable, get, set } = output;
|
|
765
|
+
defineProperty(control.subject, key, {
|
|
766
|
+
enumerable,
|
|
767
|
+
set: set === false
|
|
703
768
|
? undefined
|
|
704
|
-
:
|
|
769
|
+
: control.ref(key, set),
|
|
705
770
|
get() {
|
|
706
|
-
if (!state.has(key) && shouldSuspend)
|
|
707
|
-
throw suspend(control, key);
|
|
708
771
|
const local = subscriber(this);
|
|
709
772
|
if (local)
|
|
710
|
-
local.
|
|
711
|
-
|
|
712
|
-
?
|
|
713
|
-
|
|
773
|
+
local.follow(key);
|
|
774
|
+
try {
|
|
775
|
+
const value = get ? get(local) : control.state.get(key);
|
|
776
|
+
if (value === undefined && local && local.strict === true)
|
|
777
|
+
throw suspend(control, key);
|
|
778
|
+
return value;
|
|
779
|
+
}
|
|
780
|
+
catch (err) {
|
|
781
|
+
if (err instanceof Promise && local && local.strict === false)
|
|
782
|
+
return;
|
|
783
|
+
throw err;
|
|
784
|
+
}
|
|
714
785
|
}
|
|
715
786
|
});
|
|
716
|
-
}
|
|
717
|
-
PENDING.set(placeholder, setup);
|
|
787
|
+
});
|
|
718
788
|
return placeholder;
|
|
719
789
|
}
|
|
720
790
|
|
|
721
|
-
|
|
791
|
+
/******************************************************************************
|
|
722
792
|
Copyright (c) Microsoft Corporation.
|
|
723
793
|
|
|
724
794
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
@@ -743,7 +813,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
743
813
|
});
|
|
744
814
|
}
|
|
745
815
|
|
|
746
|
-
const Oops$
|
|
816
|
+
const Oops$6 = issues({
|
|
747
817
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
748
818
|
});
|
|
749
819
|
function run(task) {
|
|
@@ -751,7 +821,7 @@ function run(task) {
|
|
|
751
821
|
let pending = false;
|
|
752
822
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
753
823
|
if (pending)
|
|
754
|
-
return Promise.reject(Oops$
|
|
824
|
+
return Promise.reject(Oops$6.DuplicatePending(key));
|
|
755
825
|
pending = true;
|
|
756
826
|
this.update(key);
|
|
757
827
|
try {
|
|
@@ -773,106 +843,6 @@ function run(task) {
|
|
|
773
843
|
});
|
|
774
844
|
}
|
|
775
845
|
|
|
776
|
-
const Oops$8 = issues({
|
|
777
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
778
|
-
});
|
|
779
|
-
function factoryMode(self, value, key, required) {
|
|
780
|
-
const { subject, state } = self;
|
|
781
|
-
let pending;
|
|
782
|
-
let error;
|
|
783
|
-
if (value instanceof Promise) {
|
|
784
|
-
state.set(key, undefined);
|
|
785
|
-
pending = value
|
|
786
|
-
.catch(err => error = err)
|
|
787
|
-
.then(val => {
|
|
788
|
-
state.set(key, val);
|
|
789
|
-
return val;
|
|
790
|
-
})
|
|
791
|
-
.finally(() => {
|
|
792
|
-
pending = undefined;
|
|
793
|
-
self.update(key);
|
|
794
|
-
});
|
|
795
|
-
}
|
|
796
|
-
else
|
|
797
|
-
state.set(key, value);
|
|
798
|
-
const suspend = () => {
|
|
799
|
-
if (required === false)
|
|
800
|
-
return undefined;
|
|
801
|
-
const issue = Oops$8.NotReady(subject, key);
|
|
802
|
-
assign(pending, {
|
|
803
|
-
message: issue.message,
|
|
804
|
-
stack: issue.stack
|
|
805
|
-
});
|
|
806
|
-
throw pending;
|
|
807
|
-
};
|
|
808
|
-
return () => {
|
|
809
|
-
if (error)
|
|
810
|
-
throw error;
|
|
811
|
-
if (pending)
|
|
812
|
-
return suspend();
|
|
813
|
-
if (state.has(key))
|
|
814
|
-
return state.get(key);
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
|
|
818
|
-
const Oops$7 = issues({
|
|
819
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
820
|
-
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
821
|
-
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
822
|
-
});
|
|
823
|
-
function get(arg0, arg1, arg2) {
|
|
824
|
-
return add(function get(key) {
|
|
825
|
-
const { subject } = this;
|
|
826
|
-
const computeRequired = arg1 === true || arg2 === true;
|
|
827
|
-
const factoryRequired = arg1 !== false && arg2 !== false;
|
|
828
|
-
let getter;
|
|
829
|
-
// Easy mistake, using a peer, will always be unresolved.
|
|
830
|
-
if (typeof arg0 == "symbol")
|
|
831
|
-
throw Oops$7.PeerNotAllowed(subject, key);
|
|
832
|
-
// if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
|
|
833
|
-
// throw Oops.BadSource(subject, key, arg0);
|
|
834
|
-
this.state.set(key, undefined);
|
|
835
|
-
const init = () => {
|
|
836
|
-
let source = this;
|
|
837
|
-
let setter;
|
|
838
|
-
if (typeof arg0 == "function") {
|
|
839
|
-
let result = mayRetry(arg0.bind(subject, key, subject));
|
|
840
|
-
if (typeof result == "function")
|
|
841
|
-
setter = result;
|
|
842
|
-
else {
|
|
843
|
-
getter = factoryMode(this, result, key, factoryRequired);
|
|
844
|
-
return;
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
else if (arg0 instanceof Promise) {
|
|
848
|
-
getter = factoryMode(this, arg0, key, factoryRequired);
|
|
849
|
-
return;
|
|
850
|
-
}
|
|
851
|
-
else if (typeof arg1 == "function") {
|
|
852
|
-
// replace source controller in-case it is different
|
|
853
|
-
source = control(arg0);
|
|
854
|
-
setter = arg1;
|
|
855
|
-
}
|
|
856
|
-
else
|
|
857
|
-
throw new Error(`Factory argument cannot be ${arg1}`);
|
|
858
|
-
getter = computeMode(this, source, setter, key, computeRequired);
|
|
859
|
-
};
|
|
860
|
-
if (typeof arg0 == "function" && computeRequired)
|
|
861
|
-
try {
|
|
862
|
-
init();
|
|
863
|
-
}
|
|
864
|
-
catch (err) {
|
|
865
|
-
Oops$7.ComputeFailed(subject, key).warn();
|
|
866
|
-
throw err;
|
|
867
|
-
}
|
|
868
|
-
return () => {
|
|
869
|
-
if (!getter)
|
|
870
|
-
init();
|
|
871
|
-
return getter();
|
|
872
|
-
};
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
|
-
|
|
876
846
|
function ref(arg, mapper) {
|
|
877
847
|
return add(function ref(key) {
|
|
878
848
|
let value = {};
|
|
@@ -892,7 +862,7 @@ function ref(arg, mapper) {
|
|
|
892
862
|
value: createRef(this, key)
|
|
893
863
|
});
|
|
894
864
|
});
|
|
895
|
-
|
|
865
|
+
defineProperty(this.subject, key, { value });
|
|
896
866
|
});
|
|
897
867
|
}
|
|
898
868
|
function createRef(src, key, cb) {
|
|
@@ -904,16 +874,78 @@ function createRef(src, key, cb) {
|
|
|
904
874
|
return refObjectFunction;
|
|
905
875
|
}
|
|
906
876
|
|
|
877
|
+
const Oops$5 = issues({
|
|
878
|
+
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
879
|
+
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
880
|
+
});
|
|
907
881
|
function set(value, argument) {
|
|
908
|
-
if (!(1 in arguments)) {
|
|
909
|
-
argument = value;
|
|
910
|
-
value = undefined;
|
|
911
|
-
}
|
|
912
882
|
return add(function set(key) {
|
|
883
|
+
const { state, subject } = this;
|
|
884
|
+
if (typeof value == "function" || value instanceof Promise) {
|
|
885
|
+
const required = argument !== false;
|
|
886
|
+
let getter;
|
|
887
|
+
const init = () => {
|
|
888
|
+
try {
|
|
889
|
+
if (typeof value == "function")
|
|
890
|
+
value = mayRetry(value.bind(subject, key, subject));
|
|
891
|
+
let pending;
|
|
892
|
+
let error;
|
|
893
|
+
if (value instanceof Promise) {
|
|
894
|
+
state.set(key, undefined);
|
|
895
|
+
pending = value
|
|
896
|
+
.catch(err => error = err)
|
|
897
|
+
.then(val => {
|
|
898
|
+
state.set(key, val);
|
|
899
|
+
return val;
|
|
900
|
+
})
|
|
901
|
+
.finally(() => {
|
|
902
|
+
pending = undefined;
|
|
903
|
+
this.update(key);
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
else
|
|
907
|
+
state.set(key, value);
|
|
908
|
+
const suspend = () => {
|
|
909
|
+
if (required === false)
|
|
910
|
+
return undefined;
|
|
911
|
+
const issue = Oops$5.NotReady(subject, key);
|
|
912
|
+
assign(pending, {
|
|
913
|
+
message: issue.message,
|
|
914
|
+
stack: issue.stack
|
|
915
|
+
});
|
|
916
|
+
throw pending;
|
|
917
|
+
};
|
|
918
|
+
getter = () => {
|
|
919
|
+
if (error)
|
|
920
|
+
throw error;
|
|
921
|
+
if (pending)
|
|
922
|
+
return suspend();
|
|
923
|
+
if (state.has(key))
|
|
924
|
+
return state.get(key);
|
|
925
|
+
};
|
|
926
|
+
}
|
|
927
|
+
catch (err) {
|
|
928
|
+
Oops$5.ComputeFailed(subject, key).warn();
|
|
929
|
+
throw err;
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
if (argument === true)
|
|
933
|
+
init();
|
|
934
|
+
return () => {
|
|
935
|
+
if (!getter)
|
|
936
|
+
init();
|
|
937
|
+
return getter();
|
|
938
|
+
};
|
|
939
|
+
}
|
|
913
940
|
if (value !== undefined)
|
|
914
|
-
|
|
941
|
+
state.set(key, value);
|
|
915
942
|
return {
|
|
916
|
-
|
|
943
|
+
get: () => {
|
|
944
|
+
if (state.has(key))
|
|
945
|
+
return state.get(key);
|
|
946
|
+
else
|
|
947
|
+
throw suspend(this, key);
|
|
948
|
+
},
|
|
917
949
|
set: typeof argument == "function"
|
|
918
950
|
? createValueEffect(argument)
|
|
919
951
|
: undefined
|
|
@@ -957,7 +989,7 @@ function keyed(control, property, initial) {
|
|
|
957
989
|
}
|
|
958
990
|
}
|
|
959
991
|
}
|
|
960
|
-
local.
|
|
992
|
+
local.follow(property, false);
|
|
961
993
|
local.dependant.add({
|
|
962
994
|
commit() {
|
|
963
995
|
if (using.size === 0)
|
|
@@ -973,6 +1005,12 @@ function keyed(control, property, initial) {
|
|
|
973
1005
|
context.set(local, proxy);
|
|
974
1006
|
return proxy;
|
|
975
1007
|
}
|
|
1008
|
+
control.addListener(key => {
|
|
1009
|
+
if (key === null) {
|
|
1010
|
+
update.clear();
|
|
1011
|
+
context.clear();
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
976
1014
|
return {
|
|
977
1015
|
value: initial,
|
|
978
1016
|
get(local) {
|
|
@@ -985,10 +1023,6 @@ function keyed(control, property, initial) {
|
|
|
985
1023
|
managed = init(next);
|
|
986
1024
|
context.clear();
|
|
987
1025
|
emit(ANY);
|
|
988
|
-
},
|
|
989
|
-
destroy() {
|
|
990
|
-
update.clear();
|
|
991
|
-
context.clear();
|
|
992
1026
|
}
|
|
993
1027
|
};
|
|
994
1028
|
}
|
|
@@ -1067,11 +1101,11 @@ function createProxy(emit, watch) {
|
|
|
1067
1101
|
};
|
|
1068
1102
|
}
|
|
1069
1103
|
|
|
1070
|
-
const Oops$
|
|
1104
|
+
const Oops$4 = issues({
|
|
1071
1105
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1072
1106
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
1073
1107
|
});
|
|
1074
|
-
function use
|
|
1108
|
+
function use(input, argument) {
|
|
1075
1109
|
return add(function use(key) {
|
|
1076
1110
|
const { state, subject } = this;
|
|
1077
1111
|
const required = argument !== false;
|
|
@@ -1083,7 +1117,7 @@ function use$1(input, argument) {
|
|
|
1083
1117
|
input = new input();
|
|
1084
1118
|
}
|
|
1085
1119
|
else if (input && typeof input !== "object")
|
|
1086
|
-
throw Oops$
|
|
1120
|
+
throw Oops$4.BadArgument(typeof input);
|
|
1087
1121
|
if (input instanceof Map || input instanceof Set)
|
|
1088
1122
|
return keyed(this, key, input);
|
|
1089
1123
|
const onUpdate = (next) => {
|
|
@@ -1100,7 +1134,7 @@ function use$1(input, argument) {
|
|
|
1100
1134
|
const suspend = () => {
|
|
1101
1135
|
if (required === false)
|
|
1102
1136
|
return;
|
|
1103
|
-
const issue = Oops$
|
|
1137
|
+
const issue = Oops$4.NotReady(subject, key);
|
|
1104
1138
|
assign(pending, {
|
|
1105
1139
|
message: issue.message,
|
|
1106
1140
|
stack: issue.stack
|
|
@@ -1145,33 +1179,11 @@ function use$1(input, argument) {
|
|
|
1145
1179
|
});
|
|
1146
1180
|
}
|
|
1147
1181
|
|
|
1148
|
-
|
|
1149
|
-
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
1150
|
-
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
1151
|
-
});
|
|
1152
|
-
function has(Type, required) {
|
|
1153
|
-
return add(function parent() {
|
|
1154
|
-
const child = this.subject;
|
|
1155
|
-
const value = Parent.get(child);
|
|
1156
|
-
const expected = Type.name;
|
|
1157
|
-
if (!value) {
|
|
1158
|
-
if (required !== false)
|
|
1159
|
-
throw Oops$5.Required(expected, child);
|
|
1160
|
-
}
|
|
1161
|
-
else if (!(value instanceof Type))
|
|
1162
|
-
throw Oops$5.Unexpected(expected, child, value);
|
|
1163
|
-
return { value };
|
|
1164
|
-
});
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
const Oops$4 = issues({
|
|
1168
|
-
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1169
|
-
});
|
|
1170
|
-
class Lookup {
|
|
1182
|
+
class Register {
|
|
1171
1183
|
constructor() {
|
|
1172
1184
|
this.table = new Map();
|
|
1173
1185
|
}
|
|
1174
|
-
|
|
1186
|
+
has(T) {
|
|
1175
1187
|
let key = this.table.get(T);
|
|
1176
1188
|
if (!key) {
|
|
1177
1189
|
key = Symbol(T.name);
|
|
@@ -1180,22 +1192,9 @@ class Lookup {
|
|
|
1180
1192
|
return key;
|
|
1181
1193
|
}
|
|
1182
1194
|
get(Type) {
|
|
1183
|
-
return this[this.
|
|
1184
|
-
}
|
|
1185
|
-
has(key, input, callback) {
|
|
1186
|
-
if (MVC.isTypeof(input) && input.global)
|
|
1187
|
-
return input.new();
|
|
1188
|
-
if (this.register.get(key) === input)
|
|
1189
|
-
return typeof input == "object"
|
|
1190
|
-
? input
|
|
1191
|
-
: this.get(input);
|
|
1192
|
-
const instance = this.add(input);
|
|
1193
|
-
this.register.set(key, input);
|
|
1194
|
-
if (callback)
|
|
1195
|
-
callback(instance);
|
|
1196
|
-
return instance;
|
|
1195
|
+
return this[this.has(Type)];
|
|
1197
1196
|
}
|
|
1198
|
-
add(input) {
|
|
1197
|
+
add(input, key) {
|
|
1199
1198
|
let writable = true;
|
|
1200
1199
|
let T;
|
|
1201
1200
|
let I;
|
|
@@ -1204,12 +1203,12 @@ class Lookup {
|
|
|
1204
1203
|
I = new input();
|
|
1205
1204
|
}
|
|
1206
1205
|
else {
|
|
1207
|
-
I = input;
|
|
1206
|
+
I = input.is;
|
|
1208
1207
|
T = I.constructor;
|
|
1209
1208
|
writable = false;
|
|
1210
1209
|
}
|
|
1211
1210
|
do {
|
|
1212
|
-
const key = this.
|
|
1211
|
+
const key = this.has(T);
|
|
1213
1212
|
defineProperty(this, key, {
|
|
1214
1213
|
configurable: true,
|
|
1215
1214
|
value: this.hasOwnProperty(key) ? null : I,
|
|
@@ -1217,6 +1216,8 @@ class Lookup {
|
|
|
1217
1216
|
});
|
|
1218
1217
|
T = getPrototypeOf(T);
|
|
1219
1218
|
} while (T !== Model);
|
|
1219
|
+
if (key !== undefined)
|
|
1220
|
+
this.register.set(key, input);
|
|
1220
1221
|
return I;
|
|
1221
1222
|
}
|
|
1222
1223
|
push() {
|
|
@@ -1230,52 +1231,74 @@ class Lookup {
|
|
|
1230
1231
|
const entry = getOwnPropertyDescriptor(this, key);
|
|
1231
1232
|
if (entry.writable && entry.value)
|
|
1232
1233
|
items.add(entry.value);
|
|
1234
|
+
delete this[key];
|
|
1233
1235
|
}
|
|
1234
1236
|
for (const model of items)
|
|
1235
1237
|
model.end();
|
|
1236
1238
|
}
|
|
1239
|
+
delete(instance) {
|
|
1240
|
+
for (const key of getOwnPropertySymbols(this)) {
|
|
1241
|
+
const entry = getOwnPropertyDescriptor(this, key);
|
|
1242
|
+
if (entry.value === instance)
|
|
1243
|
+
delete this[key];
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
const Global$1 = new Register();
|
|
1248
|
+
|
|
1249
|
+
const Oops$3 = issues({
|
|
1250
|
+
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`,
|
|
1251
|
+
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.`,
|
|
1252
|
+
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1253
|
+
});
|
|
1254
|
+
const LookupContext = React__default["default"].createContext(Global$1);
|
|
1255
|
+
function useLookup() {
|
|
1256
|
+
try {
|
|
1257
|
+
return React__default["default"].useContext(LookupContext);
|
|
1258
|
+
}
|
|
1259
|
+
catch (err) {
|
|
1260
|
+
return Global$1;
|
|
1261
|
+
}
|
|
1237
1262
|
}
|
|
1238
|
-
const LookupContext = React__default["default"].createContext(new Lookup());
|
|
1239
|
-
const useLookup = () => React__default["default"].useContext(LookupContext);
|
|
1240
1263
|
function useContext(Type, required) {
|
|
1241
1264
|
const instance = useLookup().get(Type);
|
|
1242
1265
|
if (!instance && required !== false)
|
|
1243
|
-
throw
|
|
1266
|
+
throw MVC.isTypeof(Type) && Type.global
|
|
1267
|
+
? Oops$3.DoesNotExist(Type.name)
|
|
1268
|
+
: Oops$3.NotFound(Type.name);
|
|
1244
1269
|
return instance;
|
|
1245
1270
|
}
|
|
1246
1271
|
|
|
1247
|
-
const Oops$
|
|
1272
|
+
const Oops$2 = issues({
|
|
1248
1273
|
NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
1249
|
-
AmbientRequired: (requested, requester
|
|
1274
|
+
AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
|
|
1250
1275
|
});
|
|
1251
1276
|
const Pending = new WeakMap();
|
|
1252
1277
|
const Applied = new WeakMap();
|
|
1253
|
-
function
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
throw Oops$3.NotAllowed(subject, type.name);
|
|
1263
|
-
getPending(subject).push(context => {
|
|
1264
|
-
let instance = context.get(type);
|
|
1265
|
-
if (typeof argument == "function") {
|
|
1266
|
-
if (argument(instance) === false)
|
|
1267
|
-
instance = undefined;
|
|
1278
|
+
function getContextForGetInstruction(type, relativeTo, required) {
|
|
1279
|
+
let item = getParent(type, relativeTo);
|
|
1280
|
+
return (refresh) => {
|
|
1281
|
+
if (item)
|
|
1282
|
+
return item;
|
|
1283
|
+
findRelative(relativeTo, type, got => {
|
|
1284
|
+
if (got) {
|
|
1285
|
+
item = got;
|
|
1286
|
+
refresh(got);
|
|
1268
1287
|
}
|
|
1269
|
-
else if (
|
|
1270
|
-
throw Oops$
|
|
1271
|
-
|
|
1272
|
-
|
|
1288
|
+
else if (required)
|
|
1289
|
+
throw Oops$2.AmbientRequired(type.name, relativeTo);
|
|
1290
|
+
});
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
function findRelative(from, type, callback) {
|
|
1294
|
+
if (MVC.isTypeof(type) && type.global)
|
|
1295
|
+
callback(Global$1.get(type));
|
|
1296
|
+
else if (from.constructor.global)
|
|
1297
|
+
throw Oops$2.NotAllowed(from, type.name);
|
|
1298
|
+
else
|
|
1299
|
+
getPending(from).push(context => {
|
|
1300
|
+
callback(context.get(type));
|
|
1273
1301
|
});
|
|
1274
|
-
return {
|
|
1275
|
-
recursive: true,
|
|
1276
|
-
suspend: true
|
|
1277
|
-
};
|
|
1278
|
-
});
|
|
1279
1302
|
}
|
|
1280
1303
|
function usePeerContext(subject) {
|
|
1281
1304
|
if (Applied.has(subject)) {
|
|
@@ -1299,7 +1322,7 @@ function getPending(subject) {
|
|
|
1299
1322
|
return pending;
|
|
1300
1323
|
}
|
|
1301
1324
|
|
|
1302
|
-
function
|
|
1325
|
+
function useModel(source, arg1, arg2) {
|
|
1303
1326
|
const instance = React__default["default"].useMemo(() => {
|
|
1304
1327
|
const callback = arg2 || arg1;
|
|
1305
1328
|
const instance = Model.isTypeof(source)
|
|
@@ -1312,7 +1335,7 @@ function useNew(source, arg1, arg2) {
|
|
|
1312
1335
|
}, []);
|
|
1313
1336
|
usePeerContext(instance);
|
|
1314
1337
|
if (Array.isArray(arg1)) {
|
|
1315
|
-
const update =
|
|
1338
|
+
const update = React__default["default"].useState(0)[1];
|
|
1316
1339
|
React__default["default"].useLayoutEffect(() => {
|
|
1317
1340
|
if (arg1.length && instance instanceof Model)
|
|
1318
1341
|
instance.on(arg1, () => update(x => x + 1));
|
|
@@ -1326,19 +1349,10 @@ function useNew(source, arg1, arg2) {
|
|
|
1326
1349
|
const state = React__default["default"].useState(0);
|
|
1327
1350
|
const local = React__default["default"].useMemo(() => {
|
|
1328
1351
|
const refresh = state[1].bind(null, x => x + 1);
|
|
1329
|
-
return control(instance)
|
|
1352
|
+
return new Subscriber(control(instance), () => refresh);
|
|
1330
1353
|
}, []);
|
|
1331
|
-
if (typeof arg1 == "object")
|
|
1332
|
-
|
|
1333
|
-
let keys = arg2;
|
|
1334
|
-
local.active = false;
|
|
1335
|
-
if (!keys)
|
|
1336
|
-
keys = getOwnPropertyNames(subject);
|
|
1337
|
-
for (const key of keys)
|
|
1338
|
-
if (key in arg1)
|
|
1339
|
-
subject[key] = arg1[key];
|
|
1340
|
-
waiting.add(() => local.active = true);
|
|
1341
|
-
}
|
|
1354
|
+
if (typeof arg1 == "object")
|
|
1355
|
+
local.apply(arg1, arg2);
|
|
1342
1356
|
React__default["default"].useLayoutEffect(() => {
|
|
1343
1357
|
local.commit();
|
|
1344
1358
|
return () => {
|
|
@@ -1350,19 +1364,22 @@ function useNew(source, arg1, arg2) {
|
|
|
1350
1364
|
return local.proxy;
|
|
1351
1365
|
}
|
|
1352
1366
|
|
|
1353
|
-
function
|
|
1367
|
+
function useTap(source, arg1, arg2) {
|
|
1368
|
+
const instance = typeof source == "object"
|
|
1369
|
+
? source
|
|
1370
|
+
: "get" in source
|
|
1371
|
+
? source.get()
|
|
1372
|
+
: source();
|
|
1373
|
+
const deps = [uid(instance)];
|
|
1354
1374
|
const state = React__default["default"].useState(0);
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
const deps = [uid(source)];
|
|
1362
|
-
const local = use(refresh => {
|
|
1363
|
-
const sub = control(source).subscribe(() => update);
|
|
1375
|
+
const local = React__default["default"].useMemo(() => {
|
|
1376
|
+
const refresh = state[1].bind(null, x => x + 1);
|
|
1377
|
+
const controller = control(instance);
|
|
1378
|
+
if (typeof arg1 != "function")
|
|
1379
|
+
return new Subscriber(controller, () => refresh, arg1);
|
|
1380
|
+
const sub = new Subscriber(controller, () => update);
|
|
1364
1381
|
const spy = sub.proxy;
|
|
1365
|
-
let make = () =>
|
|
1382
|
+
let make = () => arg1.call(spy, spy, forceUpdate);
|
|
1366
1383
|
function forceUpdate(passthru) {
|
|
1367
1384
|
if (typeof passthru == "function")
|
|
1368
1385
|
passthru = passthru();
|
|
@@ -1393,7 +1410,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1393
1410
|
if (typeof value == "function") {
|
|
1394
1411
|
const get = value;
|
|
1395
1412
|
sub.watch.clear();
|
|
1396
|
-
|
|
1413
|
+
arg1 = () => get();
|
|
1397
1414
|
value = get();
|
|
1398
1415
|
}
|
|
1399
1416
|
if (value instanceof Promise) {
|
|
@@ -1404,7 +1421,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1404
1421
|
sub.commit();
|
|
1405
1422
|
update = () => {
|
|
1406
1423
|
const next = make();
|
|
1407
|
-
if (value
|
|
1424
|
+
if (notEqual(value, next))
|
|
1408
1425
|
reassign(next);
|
|
1409
1426
|
};
|
|
1410
1427
|
}
|
|
@@ -1412,7 +1429,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1412
1429
|
get() {
|
|
1413
1430
|
if (value !== undefined)
|
|
1414
1431
|
return value;
|
|
1415
|
-
if (
|
|
1432
|
+
if (arg2)
|
|
1416
1433
|
throw new Promise(res => retry = res);
|
|
1417
1434
|
return null;
|
|
1418
1435
|
}
|
|
@@ -1421,67 +1438,47 @@ function useCompute(source, compute, suspend) {
|
|
|
1421
1438
|
}, deps);
|
|
1422
1439
|
if (!local)
|
|
1423
1440
|
return null;
|
|
1424
|
-
React__default["default"].useLayoutEffect(() =>
|
|
1441
|
+
React__default["default"].useLayoutEffect(() => {
|
|
1442
|
+
local.commit();
|
|
1443
|
+
return () => local.release();
|
|
1444
|
+
}, deps);
|
|
1425
1445
|
return local.proxy;
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
function useTap(source, arg1, arg2) {
|
|
1429
|
-
const instance = typeof source == "object"
|
|
1430
|
-
? source
|
|
1431
|
-
: "get" in source
|
|
1432
|
-
? source.get()
|
|
1433
|
-
: useContext(source);
|
|
1434
|
-
return typeof arg1 == "function"
|
|
1435
|
-
? useCompute(instance, arg1, arg2)
|
|
1436
|
-
: useSubscribe(instance, arg1, arg2);
|
|
1437
1446
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
return local.proxy;
|
|
1444
|
-
const value = local.proxy[path];
|
|
1445
|
-
if (value === undefined && expect)
|
|
1446
|
-
throw suspend(local.parent, path);
|
|
1447
|
-
return value;
|
|
1448
|
-
}
|
|
1447
|
+
/** Values are not equal for purposes of a refresh. */
|
|
1448
|
+
const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
|
|
1449
|
+
!Array.isArray(b) ||
|
|
1450
|
+
a.length !== b.length ||
|
|
1451
|
+
a.some((x, i) => x !== b[i])));
|
|
1449
1452
|
|
|
1450
|
-
const Global$1 = new WeakMap();
|
|
1451
|
-
const Oops$2 = issues({
|
|
1452
|
-
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.`,
|
|
1453
|
-
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1454
|
-
});
|
|
1455
1453
|
class MVC extends Model {
|
|
1456
1454
|
end(force) {
|
|
1457
1455
|
const type = this.constructor;
|
|
1458
1456
|
if (type.keepAlive && !force)
|
|
1459
1457
|
return false;
|
|
1460
1458
|
super.end();
|
|
1461
|
-
Global$1.delete(
|
|
1459
|
+
Global$1.delete(this);
|
|
1462
1460
|
return true;
|
|
1463
1461
|
}
|
|
1464
1462
|
static new(...args) {
|
|
1465
|
-
|
|
1463
|
+
const exists = Global$1.get(this);
|
|
1464
|
+
if (exists)
|
|
1466
1465
|
if (this.keepAlive)
|
|
1467
|
-
return
|
|
1466
|
+
return exists;
|
|
1468
1467
|
else
|
|
1469
|
-
throw Oops$
|
|
1468
|
+
throw Oops$3.AlreadyExists(this.name);
|
|
1470
1469
|
const instance = super.new(...args);
|
|
1471
1470
|
if (this.global)
|
|
1472
|
-
Global$1.
|
|
1471
|
+
Global$1.add(instance);
|
|
1473
1472
|
return instance;
|
|
1474
1473
|
}
|
|
1475
1474
|
static get(arg1, arg2) {
|
|
1476
|
-
let instance;
|
|
1477
1475
|
const required = arg1 === undefined || arg1 === true;
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
instance = useContext(this, required);
|
|
1476
|
+
const instance = useContext(this, required);
|
|
1477
|
+
if (typeof arg1 === "function" && instance)
|
|
1478
|
+
callback(arg1);
|
|
1479
|
+
else if (arg2)
|
|
1480
|
+
callback(arg2);
|
|
1481
|
+
return instance;
|
|
1485
1482
|
function callback(effect) {
|
|
1486
1483
|
try {
|
|
1487
1484
|
React__default["default"].useLayoutEffect(() => effect(instance), []);
|
|
@@ -1493,29 +1490,18 @@ class MVC extends Model {
|
|
|
1493
1490
|
effect(undefined);
|
|
1494
1491
|
}
|
|
1495
1492
|
}
|
|
1496
|
-
if (typeof arg1 === "string")
|
|
1497
|
-
return instance[arg1];
|
|
1498
|
-
if (typeof arg1 === "function" && instance)
|
|
1499
|
-
callback(arg1);
|
|
1500
|
-
else if (arg2)
|
|
1501
|
-
callback(arg2);
|
|
1502
|
-
return instance;
|
|
1503
1493
|
}
|
|
1504
1494
|
static tap(arg1, arg2) {
|
|
1505
|
-
|
|
1506
|
-
return typeof arg1 == "function"
|
|
1507
|
-
? useCompute(instance, arg1, arg2)
|
|
1508
|
-
: useSubscribe(instance, arg1, arg2);
|
|
1495
|
+
return useTap(this, arg1, arg2);
|
|
1509
1496
|
}
|
|
1510
1497
|
static use(a, b) {
|
|
1511
|
-
return
|
|
1498
|
+
return useModel(this, a, b);
|
|
1512
1499
|
}
|
|
1513
1500
|
static meta(arg1, arg2) {
|
|
1514
|
-
return
|
|
1515
|
-
? useCompute(this, arg1, arg2)
|
|
1516
|
-
: useSubscribe(this, arg1, arg2);
|
|
1501
|
+
return useTap(() => this, arg1, arg2);
|
|
1517
1502
|
}
|
|
1518
|
-
}
|
|
1503
|
+
}
|
|
1504
|
+
FindInstruction.set(MVC, getContextForGetInstruction);
|
|
1519
1505
|
|
|
1520
1506
|
const Oops$1 = issues({
|
|
1521
1507
|
BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
@@ -1549,8 +1535,17 @@ function useNewContext(include, assign) {
|
|
|
1549
1535
|
throw Oops.NoType();
|
|
1550
1536
|
return ambient.push();
|
|
1551
1537
|
}, []);
|
|
1552
|
-
function register(key,
|
|
1553
|
-
|
|
1538
|
+
function register(key, input) {
|
|
1539
|
+
let instance;
|
|
1540
|
+
if (MVC.isTypeof(input) && input.global)
|
|
1541
|
+
instance = input.new();
|
|
1542
|
+
else if (context.register.get(key) === input)
|
|
1543
|
+
instance = typeof input == "object"
|
|
1544
|
+
? input
|
|
1545
|
+
: context.get(input);
|
|
1546
|
+
else
|
|
1547
|
+
instance = context.add(input, key);
|
|
1548
|
+
init.add(instance);
|
|
1554
1549
|
if (assign)
|
|
1555
1550
|
assignWeak(instance, assign);
|
|
1556
1551
|
}
|
|
@@ -1622,12 +1617,7 @@ exports.Provider = Provider;
|
|
|
1622
1617
|
exports.add = add;
|
|
1623
1618
|
exports["default"] = MVC;
|
|
1624
1619
|
exports.get = get;
|
|
1625
|
-
exports.has = has;
|
|
1626
1620
|
exports.ref = ref;
|
|
1627
1621
|
exports.run = run;
|
|
1628
1622
|
exports.set = set;
|
|
1629
|
-
exports.
|
|
1630
|
-
exports.use = use$1;
|
|
1631
|
-
exports.useContext = useContext;
|
|
1632
|
-
exports.useNew = useNew;
|
|
1633
|
-
exports.useTap = useTap;
|
|
1623
|
+
exports.use = use;
|