@expressive/mvc 0.16.0 → 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 +105 -158
- package/lib/index.esm.js +531 -552
- package/lib/index.js +530 -556
- 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,68 +381,7 @@ function awaitUpdate(source, arg1, arg2) {
|
|
|
320
381
|
});
|
|
321
382
|
}
|
|
322
383
|
|
|
323
|
-
const
|
|
324
|
-
class Subscriber {
|
|
325
|
-
constructor(parent, onUpdate, suspend) {
|
|
326
|
-
this.parent = parent;
|
|
327
|
-
this.onUpdate = onUpdate;
|
|
328
|
-
this.suspend = suspend;
|
|
329
|
-
this.active = false;
|
|
330
|
-
this.dependant = new Set();
|
|
331
|
-
this.watch = new Map();
|
|
332
|
-
const proxy = create(parent.subject);
|
|
333
|
-
const reset = () => this.latest = undefined;
|
|
334
|
-
REGISTER$1.set(proxy, this);
|
|
335
|
-
defineProperty(this, "proxy", {
|
|
336
|
-
configurable: true,
|
|
337
|
-
get() {
|
|
338
|
-
setTimeout(reset, 0);
|
|
339
|
-
return proxy;
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
get using() {
|
|
344
|
-
return Array.from(this.watch.keys());
|
|
345
|
-
}
|
|
346
|
-
add(key, value) {
|
|
347
|
-
if (value !== undefined)
|
|
348
|
-
this.watch.set(key, value);
|
|
349
|
-
else if (!this.watch.has(key))
|
|
350
|
-
this.watch.set(key, true);
|
|
351
|
-
}
|
|
352
|
-
commit() {
|
|
353
|
-
const release = this.parent.addListener(key => {
|
|
354
|
-
if (this.active)
|
|
355
|
-
this.onEvent(key);
|
|
356
|
-
});
|
|
357
|
-
this.active = true;
|
|
358
|
-
this.dependant.forEach(x => x.commit());
|
|
359
|
-
return this.release = () => {
|
|
360
|
-
this.dependant.forEach(x => x.release());
|
|
361
|
-
release();
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
onEvent(key) {
|
|
365
|
-
const { parent, watch } = this;
|
|
366
|
-
let handler = watch.get(key);
|
|
367
|
-
if (typeof handler == "function")
|
|
368
|
-
handler = handler();
|
|
369
|
-
if (handler) {
|
|
370
|
-
const notify = this.onUpdate(key, parent);
|
|
371
|
-
if (notify) {
|
|
372
|
-
parent.waiting.add(update => {
|
|
373
|
-
this.latest = update.filter(k => watch.has(k));
|
|
374
|
-
});
|
|
375
|
-
parent.waiting.add(notify);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
function subscriber(from) {
|
|
381
|
-
return REGISTER$1.get(from);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
const Oops$b = issues({
|
|
384
|
+
const Oops$8 = issues({
|
|
385
385
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
386
386
|
});
|
|
387
387
|
class Model {
|
|
@@ -439,7 +439,7 @@ class Model {
|
|
|
439
439
|
return {
|
|
440
440
|
then: (callback) => {
|
|
441
441
|
if (!callback)
|
|
442
|
-
throw Oops$
|
|
442
|
+
throw Oops$8.NoChaining();
|
|
443
443
|
controller.waiting.add(callback);
|
|
444
444
|
}
|
|
445
445
|
};
|
|
@@ -472,11 +472,150 @@ class Model {
|
|
|
472
472
|
maybe.prototype instanceof this);
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
|
-
defineProperty(Model.prototype, "toString", {
|
|
476
|
-
value() {
|
|
477
|
-
return this.constructor.name;
|
|
478
|
-
}
|
|
479
|
-
});
|
|
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
|
+
}
|
|
480
619
|
|
|
481
620
|
const REGISTER = new WeakMap();
|
|
482
621
|
const PENDING = new Map();
|
|
@@ -488,9 +627,6 @@ class Control {
|
|
|
488
627
|
this.followers = new Set();
|
|
489
628
|
REGISTER.set(subject, this);
|
|
490
629
|
}
|
|
491
|
-
subscribe(callback) {
|
|
492
|
-
return new Subscriber(this, callback);
|
|
493
|
-
}
|
|
494
630
|
watch(key) {
|
|
495
631
|
const { subject, state } = this;
|
|
496
632
|
const { value } = getOwnPropertyDescriptor(subject, key);
|
|
@@ -501,7 +637,7 @@ class Control {
|
|
|
501
637
|
if (instruction) {
|
|
502
638
|
delete subject[key];
|
|
503
639
|
PENDING.delete(value);
|
|
504
|
-
instruction
|
|
640
|
+
instruction(this, key);
|
|
505
641
|
}
|
|
506
642
|
return;
|
|
507
643
|
}
|
|
@@ -517,8 +653,8 @@ class Control {
|
|
|
517
653
|
const sub = subscriber(this);
|
|
518
654
|
const value = state.get(key);
|
|
519
655
|
if (sub) {
|
|
520
|
-
sub.
|
|
521
|
-
if (value === undefined && sub.
|
|
656
|
+
sub.follow(key);
|
|
657
|
+
if (value === undefined && sub.strict)
|
|
522
658
|
throw suspend(this, key);
|
|
523
659
|
}
|
|
524
660
|
return value;
|
|
@@ -579,6 +715,8 @@ class Control {
|
|
|
579
715
|
listeners.forEach(x => x(null, this));
|
|
580
716
|
}
|
|
581
717
|
}
|
|
718
|
+
Control.get = controller;
|
|
719
|
+
Control.for = control;
|
|
582
720
|
function controller(from) {
|
|
583
721
|
if ("is" in from)
|
|
584
722
|
from = from.is;
|
|
@@ -608,68 +746,6 @@ function control(subject, cb) {
|
|
|
608
746
|
return cb ? cb(control) : control;
|
|
609
747
|
}
|
|
610
748
|
|
|
611
|
-
const Parent = new WeakMap();
|
|
612
|
-
const Oops$a = issues({
|
|
613
|
-
BadAssignment: (parent, expected, got) => `Property ${parent} expected Model of type ${expected} but got ${got}.`
|
|
614
|
-
});
|
|
615
|
-
function getRecursive(key, from) {
|
|
616
|
-
const context = new WeakMap();
|
|
617
|
-
const { state } = from;
|
|
618
|
-
return (local) => {
|
|
619
|
-
if (!local)
|
|
620
|
-
return state.get(key);
|
|
621
|
-
if (!context.has(local)) {
|
|
622
|
-
let reset;
|
|
623
|
-
const init = () => {
|
|
624
|
-
if (reset)
|
|
625
|
-
reset();
|
|
626
|
-
const value = state.get(key);
|
|
627
|
-
if (value && controller(value)) {
|
|
628
|
-
const child = control(value).subscribe(local.onUpdate);
|
|
629
|
-
if (local.active)
|
|
630
|
-
child.commit();
|
|
631
|
-
local.dependant.add(child);
|
|
632
|
-
context.set(local, child.proxy);
|
|
633
|
-
reset = () => {
|
|
634
|
-
child.release();
|
|
635
|
-
local.dependant.delete(child);
|
|
636
|
-
context.set(local, undefined);
|
|
637
|
-
reset = undefined;
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
return true;
|
|
641
|
-
};
|
|
642
|
-
local.add(key, init);
|
|
643
|
-
init();
|
|
644
|
-
}
|
|
645
|
-
return context.get(local);
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
function setRecursive(controller, key, initial) {
|
|
649
|
-
const { state, subject } = controller;
|
|
650
|
-
const Type = initial.constructor;
|
|
651
|
-
let get;
|
|
652
|
-
const onUpdate = (next) => {
|
|
653
|
-
state.set(key, next);
|
|
654
|
-
if (!(next instanceof Type))
|
|
655
|
-
throw Oops$a.BadAssignment(`${subject}.${key}`, Type.name, String(next));
|
|
656
|
-
get = getRecursive(key, controller);
|
|
657
|
-
Parent.set(next, subject);
|
|
658
|
-
control(next);
|
|
659
|
-
return true;
|
|
660
|
-
};
|
|
661
|
-
onUpdate(initial);
|
|
662
|
-
defineProperty(subject, key, {
|
|
663
|
-
set: controller.ref(key, onUpdate),
|
|
664
|
-
get() {
|
|
665
|
-
const local = subscriber(this);
|
|
666
|
-
if (local)
|
|
667
|
-
local.add(key);
|
|
668
|
-
return get(local);
|
|
669
|
-
}
|
|
670
|
-
});
|
|
671
|
-
}
|
|
672
|
-
|
|
673
749
|
/**
|
|
674
750
|
* Run instruction as controller sets itself up.
|
|
675
751
|
* This will specialize the behavior of a given property.
|
|
@@ -677,64 +753,42 @@ function setRecursive(controller, key, initial) {
|
|
|
677
753
|
function add(instruction, label) {
|
|
678
754
|
const name = label || instruction.name || "pending";
|
|
679
755
|
const placeholder = Symbol(`${name} instruction`);
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
756
|
+
PENDING.set(placeholder, (control, key) => {
|
|
757
|
+
let output = instruction.call(control, key, control);
|
|
758
|
+
if (!output)
|
|
759
|
+
return undefined;
|
|
683
760
|
if (typeof output == "function")
|
|
684
761
|
output = { get: output };
|
|
685
|
-
if (typeof output != "object")
|
|
686
|
-
return;
|
|
687
|
-
if ("explicit" in output && output.explicit) {
|
|
688
|
-
defineProperty(subject, key, output);
|
|
689
|
-
return false;
|
|
690
|
-
}
|
|
691
|
-
let { get: onGet, set: onSet, suspend: shouldSuspend } = output;
|
|
692
762
|
if ("value" in output)
|
|
693
|
-
state.set(key, output.value);
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
if (destroy)
|
|
699
|
-
this.addListener((key) => {
|
|
700
|
-
if (key == null)
|
|
701
|
-
destroy();
|
|
702
|
-
});
|
|
703
|
-
}
|
|
704
|
-
const control = this;
|
|
705
|
-
defineProperty(subject, key, {
|
|
706
|
-
enumerable: output.enumerable,
|
|
707
|
-
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
|
|
708
768
|
? undefined
|
|
709
|
-
:
|
|
769
|
+
: control.ref(key, set),
|
|
710
770
|
get() {
|
|
711
|
-
if (!state.has(key) && shouldSuspend)
|
|
712
|
-
throw suspend(control, key);
|
|
713
771
|
const local = subscriber(this);
|
|
714
|
-
const required = local && local.suspend;
|
|
715
772
|
if (local)
|
|
716
|
-
local.
|
|
773
|
+
local.follow(key);
|
|
717
774
|
try {
|
|
718
|
-
const value =
|
|
719
|
-
|
|
720
|
-
: state.get(key);
|
|
721
|
-
if (value === undefined && required === true)
|
|
775
|
+
const value = get ? get(local) : control.state.get(key);
|
|
776
|
+
if (value === undefined && local && local.strict === true)
|
|
722
777
|
throw suspend(control, key);
|
|
723
778
|
return value;
|
|
724
779
|
}
|
|
725
780
|
catch (err) {
|
|
726
|
-
if (err instanceof Promise &&
|
|
781
|
+
if (err instanceof Promise && local && local.strict === false)
|
|
727
782
|
return;
|
|
728
783
|
throw err;
|
|
729
784
|
}
|
|
730
785
|
}
|
|
731
786
|
});
|
|
732
|
-
}
|
|
733
|
-
PENDING.set(placeholder, setup);
|
|
787
|
+
});
|
|
734
788
|
return placeholder;
|
|
735
789
|
}
|
|
736
790
|
|
|
737
|
-
|
|
791
|
+
/******************************************************************************
|
|
738
792
|
Copyright (c) Microsoft Corporation.
|
|
739
793
|
|
|
740
794
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
@@ -759,7 +813,7 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
759
813
|
});
|
|
760
814
|
}
|
|
761
815
|
|
|
762
|
-
const Oops$
|
|
816
|
+
const Oops$6 = issues({
|
|
763
817
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
764
818
|
});
|
|
765
819
|
function run(task) {
|
|
@@ -767,7 +821,7 @@ function run(task) {
|
|
|
767
821
|
let pending = false;
|
|
768
822
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
769
823
|
if (pending)
|
|
770
|
-
return Promise.reject(Oops$
|
|
824
|
+
return Promise.reject(Oops$6.DuplicatePending(key));
|
|
771
825
|
pending = true;
|
|
772
826
|
this.update(key);
|
|
773
827
|
try {
|
|
@@ -789,106 +843,6 @@ function run(task) {
|
|
|
789
843
|
});
|
|
790
844
|
}
|
|
791
845
|
|
|
792
|
-
const Oops$8 = issues({
|
|
793
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
794
|
-
});
|
|
795
|
-
function factoryMode(self, value, key, required) {
|
|
796
|
-
const { subject, state } = self;
|
|
797
|
-
let pending;
|
|
798
|
-
let error;
|
|
799
|
-
if (value instanceof Promise) {
|
|
800
|
-
state.set(key, undefined);
|
|
801
|
-
pending = value
|
|
802
|
-
.catch(err => error = err)
|
|
803
|
-
.then(val => {
|
|
804
|
-
state.set(key, val);
|
|
805
|
-
return val;
|
|
806
|
-
})
|
|
807
|
-
.finally(() => {
|
|
808
|
-
pending = undefined;
|
|
809
|
-
self.update(key);
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
else
|
|
813
|
-
state.set(key, value);
|
|
814
|
-
const suspend = () => {
|
|
815
|
-
if (required === false)
|
|
816
|
-
return undefined;
|
|
817
|
-
const issue = Oops$8.NotReady(subject, key);
|
|
818
|
-
assign(pending, {
|
|
819
|
-
message: issue.message,
|
|
820
|
-
stack: issue.stack
|
|
821
|
-
});
|
|
822
|
-
throw pending;
|
|
823
|
-
};
|
|
824
|
-
return () => {
|
|
825
|
-
if (error)
|
|
826
|
-
throw error;
|
|
827
|
-
if (pending)
|
|
828
|
-
return suspend();
|
|
829
|
-
if (state.has(key))
|
|
830
|
-
return state.get(key);
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
|
|
834
|
-
const Oops$7 = issues({
|
|
835
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
836
|
-
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
837
|
-
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
|
|
838
|
-
});
|
|
839
|
-
function get(arg0, arg1, arg2) {
|
|
840
|
-
return add(function get(key) {
|
|
841
|
-
const { subject } = this;
|
|
842
|
-
const computeRequired = arg1 === true || arg2 === true;
|
|
843
|
-
const factoryRequired = arg1 !== false && arg2 !== false;
|
|
844
|
-
let getter;
|
|
845
|
-
// Easy mistake, using a peer, will always be unresolved.
|
|
846
|
-
if (typeof arg0 == "symbol")
|
|
847
|
-
throw Oops$7.PeerNotAllowed(subject, key);
|
|
848
|
-
// if(typeof arg0 == "function" && /^[A-Z]/.test(arg0.name))
|
|
849
|
-
// throw Oops.BadSource(subject, key, arg0);
|
|
850
|
-
this.state.set(key, undefined);
|
|
851
|
-
const init = () => {
|
|
852
|
-
let source = this;
|
|
853
|
-
let setter;
|
|
854
|
-
if (typeof arg0 == "function") {
|
|
855
|
-
const result = mayRetry(arg0.bind(subject, key, subject));
|
|
856
|
-
if (typeof result == "function")
|
|
857
|
-
setter = result;
|
|
858
|
-
else {
|
|
859
|
-
getter = factoryMode(this, result, key, factoryRequired);
|
|
860
|
-
return;
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
else if (arg0 instanceof Promise) {
|
|
864
|
-
getter = factoryMode(this, arg0, key, factoryRequired);
|
|
865
|
-
return;
|
|
866
|
-
}
|
|
867
|
-
else if (typeof arg1 == "function") {
|
|
868
|
-
// replace source controller in-case it is different
|
|
869
|
-
source = control(arg0);
|
|
870
|
-
setter = arg1;
|
|
871
|
-
}
|
|
872
|
-
else
|
|
873
|
-
throw new Error(`Factory argument cannot be ${arg1}`);
|
|
874
|
-
getter = computeMode(this, source, setter, key, computeRequired);
|
|
875
|
-
};
|
|
876
|
-
if (typeof arg0 == "function" && computeRequired)
|
|
877
|
-
try {
|
|
878
|
-
init();
|
|
879
|
-
}
|
|
880
|
-
catch (err) {
|
|
881
|
-
Oops$7.ComputeFailed(subject, key).warn();
|
|
882
|
-
throw err;
|
|
883
|
-
}
|
|
884
|
-
return () => {
|
|
885
|
-
if (!getter)
|
|
886
|
-
init();
|
|
887
|
-
return getter();
|
|
888
|
-
};
|
|
889
|
-
});
|
|
890
|
-
}
|
|
891
|
-
|
|
892
846
|
function ref(arg, mapper) {
|
|
893
847
|
return add(function ref(key) {
|
|
894
848
|
let value = {};
|
|
@@ -908,7 +862,7 @@ function ref(arg, mapper) {
|
|
|
908
862
|
value: createRef(this, key)
|
|
909
863
|
});
|
|
910
864
|
});
|
|
911
|
-
|
|
865
|
+
defineProperty(this.subject, key, { value });
|
|
912
866
|
});
|
|
913
867
|
}
|
|
914
868
|
function createRef(src, key, cb) {
|
|
@@ -920,16 +874,78 @@ function createRef(src, key, cb) {
|
|
|
920
874
|
return refObjectFunction;
|
|
921
875
|
}
|
|
922
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
|
+
});
|
|
923
881
|
function set(value, argument) {
|
|
924
|
-
if (!(1 in arguments)) {
|
|
925
|
-
argument = value;
|
|
926
|
-
value = undefined;
|
|
927
|
-
}
|
|
928
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
|
+
}
|
|
929
940
|
if (value !== undefined)
|
|
930
|
-
|
|
941
|
+
state.set(key, value);
|
|
931
942
|
return {
|
|
932
|
-
|
|
943
|
+
get: () => {
|
|
944
|
+
if (state.has(key))
|
|
945
|
+
return state.get(key);
|
|
946
|
+
else
|
|
947
|
+
throw suspend(this, key);
|
|
948
|
+
},
|
|
933
949
|
set: typeof argument == "function"
|
|
934
950
|
? createValueEffect(argument)
|
|
935
951
|
: undefined
|
|
@@ -973,7 +989,7 @@ function keyed(control, property, initial) {
|
|
|
973
989
|
}
|
|
974
990
|
}
|
|
975
991
|
}
|
|
976
|
-
local.
|
|
992
|
+
local.follow(property, false);
|
|
977
993
|
local.dependant.add({
|
|
978
994
|
commit() {
|
|
979
995
|
if (using.size === 0)
|
|
@@ -989,6 +1005,12 @@ function keyed(control, property, initial) {
|
|
|
989
1005
|
context.set(local, proxy);
|
|
990
1006
|
return proxy;
|
|
991
1007
|
}
|
|
1008
|
+
control.addListener(key => {
|
|
1009
|
+
if (key === null) {
|
|
1010
|
+
update.clear();
|
|
1011
|
+
context.clear();
|
|
1012
|
+
}
|
|
1013
|
+
});
|
|
992
1014
|
return {
|
|
993
1015
|
value: initial,
|
|
994
1016
|
get(local) {
|
|
@@ -1001,10 +1023,6 @@ function keyed(control, property, initial) {
|
|
|
1001
1023
|
managed = init(next);
|
|
1002
1024
|
context.clear();
|
|
1003
1025
|
emit(ANY);
|
|
1004
|
-
},
|
|
1005
|
-
destroy() {
|
|
1006
|
-
update.clear();
|
|
1007
|
-
context.clear();
|
|
1008
1026
|
}
|
|
1009
1027
|
};
|
|
1010
1028
|
}
|
|
@@ -1083,11 +1101,11 @@ function createProxy(emit, watch) {
|
|
|
1083
1101
|
};
|
|
1084
1102
|
}
|
|
1085
1103
|
|
|
1086
|
-
const Oops$
|
|
1104
|
+
const Oops$4 = issues({
|
|
1087
1105
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1088
1106
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
1089
1107
|
});
|
|
1090
|
-
function use
|
|
1108
|
+
function use(input, argument) {
|
|
1091
1109
|
return add(function use(key) {
|
|
1092
1110
|
const { state, subject } = this;
|
|
1093
1111
|
const required = argument !== false;
|
|
@@ -1099,7 +1117,7 @@ function use$1(input, argument) {
|
|
|
1099
1117
|
input = new input();
|
|
1100
1118
|
}
|
|
1101
1119
|
else if (input && typeof input !== "object")
|
|
1102
|
-
throw Oops$
|
|
1120
|
+
throw Oops$4.BadArgument(typeof input);
|
|
1103
1121
|
if (input instanceof Map || input instanceof Set)
|
|
1104
1122
|
return keyed(this, key, input);
|
|
1105
1123
|
const onUpdate = (next) => {
|
|
@@ -1116,7 +1134,7 @@ function use$1(input, argument) {
|
|
|
1116
1134
|
const suspend = () => {
|
|
1117
1135
|
if (required === false)
|
|
1118
1136
|
return;
|
|
1119
|
-
const issue = Oops$
|
|
1137
|
+
const issue = Oops$4.NotReady(subject, key);
|
|
1120
1138
|
assign(pending, {
|
|
1121
1139
|
message: issue.message,
|
|
1122
1140
|
stack: issue.stack
|
|
@@ -1161,33 +1179,11 @@ function use$1(input, argument) {
|
|
|
1161
1179
|
});
|
|
1162
1180
|
}
|
|
1163
1181
|
|
|
1164
|
-
|
|
1165
|
-
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
1166
|
-
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
1167
|
-
});
|
|
1168
|
-
function has(Type, required) {
|
|
1169
|
-
return add(function parent() {
|
|
1170
|
-
const child = this.subject;
|
|
1171
|
-
const value = Parent.get(child);
|
|
1172
|
-
const expected = Type.name;
|
|
1173
|
-
if (!value) {
|
|
1174
|
-
if (required !== false)
|
|
1175
|
-
throw Oops$5.Required(expected, child);
|
|
1176
|
-
}
|
|
1177
|
-
else if (!(value instanceof Type))
|
|
1178
|
-
throw Oops$5.Unexpected(expected, child, value);
|
|
1179
|
-
return { value };
|
|
1180
|
-
});
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
const Oops$4 = issues({
|
|
1184
|
-
NotFound: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
1185
|
-
});
|
|
1186
|
-
class Lookup {
|
|
1182
|
+
class Register {
|
|
1187
1183
|
constructor() {
|
|
1188
1184
|
this.table = new Map();
|
|
1189
1185
|
}
|
|
1190
|
-
|
|
1186
|
+
has(T) {
|
|
1191
1187
|
let key = this.table.get(T);
|
|
1192
1188
|
if (!key) {
|
|
1193
1189
|
key = Symbol(T.name);
|
|
@@ -1196,22 +1192,9 @@ class Lookup {
|
|
|
1196
1192
|
return key;
|
|
1197
1193
|
}
|
|
1198
1194
|
get(Type) {
|
|
1199
|
-
return this[this.
|
|
1200
|
-
}
|
|
1201
|
-
has(key, input, callback) {
|
|
1202
|
-
if (MVC.isTypeof(input) && input.global)
|
|
1203
|
-
return input.new();
|
|
1204
|
-
if (this.register.get(key) === input)
|
|
1205
|
-
return typeof input == "object"
|
|
1206
|
-
? input
|
|
1207
|
-
: this.get(input);
|
|
1208
|
-
const instance = this.add(input);
|
|
1209
|
-
this.register.set(key, input);
|
|
1210
|
-
if (callback)
|
|
1211
|
-
callback(instance);
|
|
1212
|
-
return instance;
|
|
1195
|
+
return this[this.has(Type)];
|
|
1213
1196
|
}
|
|
1214
|
-
add(input) {
|
|
1197
|
+
add(input, key) {
|
|
1215
1198
|
let writable = true;
|
|
1216
1199
|
let T;
|
|
1217
1200
|
let I;
|
|
@@ -1220,12 +1203,12 @@ class Lookup {
|
|
|
1220
1203
|
I = new input();
|
|
1221
1204
|
}
|
|
1222
1205
|
else {
|
|
1223
|
-
I = input;
|
|
1206
|
+
I = input.is;
|
|
1224
1207
|
T = I.constructor;
|
|
1225
1208
|
writable = false;
|
|
1226
1209
|
}
|
|
1227
1210
|
do {
|
|
1228
|
-
const key = this.
|
|
1211
|
+
const key = this.has(T);
|
|
1229
1212
|
defineProperty(this, key, {
|
|
1230
1213
|
configurable: true,
|
|
1231
1214
|
value: this.hasOwnProperty(key) ? null : I,
|
|
@@ -1233,6 +1216,8 @@ class Lookup {
|
|
|
1233
1216
|
});
|
|
1234
1217
|
T = getPrototypeOf(T);
|
|
1235
1218
|
} while (T !== Model);
|
|
1219
|
+
if (key !== undefined)
|
|
1220
|
+
this.register.set(key, input);
|
|
1236
1221
|
return I;
|
|
1237
1222
|
}
|
|
1238
1223
|
push() {
|
|
@@ -1246,52 +1231,74 @@ class Lookup {
|
|
|
1246
1231
|
const entry = getOwnPropertyDescriptor(this, key);
|
|
1247
1232
|
if (entry.writable && entry.value)
|
|
1248
1233
|
items.add(entry.value);
|
|
1234
|
+
delete this[key];
|
|
1249
1235
|
}
|
|
1250
1236
|
for (const model of items)
|
|
1251
1237
|
model.end();
|
|
1252
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
|
+
}
|
|
1253
1262
|
}
|
|
1254
|
-
const LookupContext = React__default["default"].createContext(new Lookup());
|
|
1255
|
-
const useLookup = () => React__default["default"].useContext(LookupContext);
|
|
1256
1263
|
function useContext(Type, required) {
|
|
1257
1264
|
const instance = useLookup().get(Type);
|
|
1258
1265
|
if (!instance && required !== false)
|
|
1259
|
-
throw
|
|
1266
|
+
throw MVC.isTypeof(Type) && Type.global
|
|
1267
|
+
? Oops$3.DoesNotExist(Type.name)
|
|
1268
|
+
: Oops$3.NotFound(Type.name);
|
|
1260
1269
|
return instance;
|
|
1261
1270
|
}
|
|
1262
1271
|
|
|
1263
|
-
const Oops$
|
|
1272
|
+
const Oops$2 = issues({
|
|
1264
1273
|
NotAllowed: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
1265
|
-
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.`
|
|
1266
1275
|
});
|
|
1267
1276
|
const Pending = new WeakMap();
|
|
1268
1277
|
const Applied = new WeakMap();
|
|
1269
|
-
function
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
throw Oops$3.NotAllowed(subject, type.name);
|
|
1279
|
-
getPending(subject).push(context => {
|
|
1280
|
-
let instance = context.get(type);
|
|
1281
|
-
if (typeof argument == "function") {
|
|
1282
|
-
if (argument(instance) === false)
|
|
1283
|
-
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);
|
|
1284
1287
|
}
|
|
1285
|
-
else if (
|
|
1286
|
-
throw Oops$
|
|
1287
|
-
|
|
1288
|
-
|
|
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));
|
|
1289
1301
|
});
|
|
1290
|
-
return {
|
|
1291
|
-
recursive: true,
|
|
1292
|
-
suspend: true
|
|
1293
|
-
};
|
|
1294
|
-
});
|
|
1295
1302
|
}
|
|
1296
1303
|
function usePeerContext(subject) {
|
|
1297
1304
|
if (Applied.has(subject)) {
|
|
@@ -1315,7 +1322,7 @@ function getPending(subject) {
|
|
|
1315
1322
|
return pending;
|
|
1316
1323
|
}
|
|
1317
1324
|
|
|
1318
|
-
function
|
|
1325
|
+
function useModel(source, arg1, arg2) {
|
|
1319
1326
|
const instance = React__default["default"].useMemo(() => {
|
|
1320
1327
|
const callback = arg2 || arg1;
|
|
1321
1328
|
const instance = Model.isTypeof(source)
|
|
@@ -1328,7 +1335,7 @@ function useNew(source, arg1, arg2) {
|
|
|
1328
1335
|
}, []);
|
|
1329
1336
|
usePeerContext(instance);
|
|
1330
1337
|
if (Array.isArray(arg1)) {
|
|
1331
|
-
const update =
|
|
1338
|
+
const update = React__default["default"].useState(0)[1];
|
|
1332
1339
|
React__default["default"].useLayoutEffect(() => {
|
|
1333
1340
|
if (arg1.length && instance instanceof Model)
|
|
1334
1341
|
instance.on(arg1, () => update(x => x + 1));
|
|
@@ -1342,19 +1349,10 @@ function useNew(source, arg1, arg2) {
|
|
|
1342
1349
|
const state = React__default["default"].useState(0);
|
|
1343
1350
|
const local = React__default["default"].useMemo(() => {
|
|
1344
1351
|
const refresh = state[1].bind(null, x => x + 1);
|
|
1345
|
-
return control(instance)
|
|
1352
|
+
return new Subscriber(control(instance), () => refresh);
|
|
1346
1353
|
}, []);
|
|
1347
|
-
if (typeof arg1 == "object")
|
|
1348
|
-
|
|
1349
|
-
let keys = arg2;
|
|
1350
|
-
local.active = false;
|
|
1351
|
-
if (!keys)
|
|
1352
|
-
keys = getOwnPropertyNames(subject);
|
|
1353
|
-
for (const key of keys)
|
|
1354
|
-
if (key in arg1)
|
|
1355
|
-
subject[key] = arg1[key];
|
|
1356
|
-
waiting.add(() => local.active = true);
|
|
1357
|
-
}
|
|
1354
|
+
if (typeof arg1 == "object")
|
|
1355
|
+
local.apply(arg1, arg2);
|
|
1358
1356
|
React__default["default"].useLayoutEffect(() => {
|
|
1359
1357
|
local.commit();
|
|
1360
1358
|
return () => {
|
|
@@ -1366,19 +1364,22 @@ function useNew(source, arg1, arg2) {
|
|
|
1366
1364
|
return local.proxy;
|
|
1367
1365
|
}
|
|
1368
1366
|
|
|
1369
|
-
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)];
|
|
1370
1374
|
const state = React__default["default"].useState(0);
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
const deps = [uid(source)];
|
|
1378
|
-
const local = use(refresh => {
|
|
1379
|
-
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);
|
|
1380
1381
|
const spy = sub.proxy;
|
|
1381
|
-
let make = () =>
|
|
1382
|
+
let make = () => arg1.call(spy, spy, forceUpdate);
|
|
1382
1383
|
function forceUpdate(passthru) {
|
|
1383
1384
|
if (typeof passthru == "function")
|
|
1384
1385
|
passthru = passthru();
|
|
@@ -1409,7 +1410,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1409
1410
|
if (typeof value == "function") {
|
|
1410
1411
|
const get = value;
|
|
1411
1412
|
sub.watch.clear();
|
|
1412
|
-
|
|
1413
|
+
arg1 = () => get();
|
|
1413
1414
|
value = get();
|
|
1414
1415
|
}
|
|
1415
1416
|
if (value instanceof Promise) {
|
|
@@ -1428,7 +1429,7 @@ function useCompute(source, compute, suspend) {
|
|
|
1428
1429
|
get() {
|
|
1429
1430
|
if (value !== undefined)
|
|
1430
1431
|
return value;
|
|
1431
|
-
if (
|
|
1432
|
+
if (arg2)
|
|
1432
1433
|
throw new Promise(res => retry = res);
|
|
1433
1434
|
return null;
|
|
1434
1435
|
}
|
|
@@ -1437,7 +1438,10 @@ function useCompute(source, compute, suspend) {
|
|
|
1437
1438
|
}, deps);
|
|
1438
1439
|
if (!local)
|
|
1439
1440
|
return null;
|
|
1440
|
-
React__default["default"].useLayoutEffect(() =>
|
|
1441
|
+
React__default["default"].useLayoutEffect(() => {
|
|
1442
|
+
local.commit();
|
|
1443
|
+
return () => local.release();
|
|
1444
|
+
}, deps);
|
|
1441
1445
|
return local.proxy;
|
|
1442
1446
|
}
|
|
1443
1447
|
/** Values are not equal for purposes of a refresh. */
|
|
@@ -1446,58 +1450,35 @@ const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
|
|
|
1446
1450
|
a.length !== b.length ||
|
|
1447
1451
|
a.some((x, i) => x !== b[i])));
|
|
1448
1452
|
|
|
1449
|
-
function useTap(source, arg1, arg2) {
|
|
1450
|
-
const instance = typeof source == "object"
|
|
1451
|
-
? source
|
|
1452
|
-
: "get" in source
|
|
1453
|
-
? source.get()
|
|
1454
|
-
: useContext(source);
|
|
1455
|
-
return typeof arg1 == "function"
|
|
1456
|
-
? useCompute(instance, arg1, arg2)
|
|
1457
|
-
: useSubscribe(instance, arg1);
|
|
1458
|
-
}
|
|
1459
|
-
function useSubscribe(source, expect) {
|
|
1460
|
-
const deps = [uid(source)];
|
|
1461
|
-
const local = use(refresh => (new Subscriber(control(source), () => refresh, expect)), deps);
|
|
1462
|
-
React__default["default"].useLayoutEffect(() => local.commit(), deps);
|
|
1463
|
-
return local.proxy;
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
const Global$1 = new WeakMap();
|
|
1467
|
-
const Oops$2 = issues({
|
|
1468
|
-
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.`,
|
|
1469
|
-
AlreadyExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1470
|
-
});
|
|
1471
1453
|
class MVC extends Model {
|
|
1472
1454
|
end(force) {
|
|
1473
1455
|
const type = this.constructor;
|
|
1474
1456
|
if (type.keepAlive && !force)
|
|
1475
1457
|
return false;
|
|
1476
1458
|
super.end();
|
|
1477
|
-
Global$1.delete(
|
|
1459
|
+
Global$1.delete(this);
|
|
1478
1460
|
return true;
|
|
1479
1461
|
}
|
|
1480
1462
|
static new(...args) {
|
|
1481
|
-
|
|
1463
|
+
const exists = Global$1.get(this);
|
|
1464
|
+
if (exists)
|
|
1482
1465
|
if (this.keepAlive)
|
|
1483
|
-
return
|
|
1466
|
+
return exists;
|
|
1484
1467
|
else
|
|
1485
|
-
throw Oops$
|
|
1468
|
+
throw Oops$3.AlreadyExists(this.name);
|
|
1486
1469
|
const instance = super.new(...args);
|
|
1487
1470
|
if (this.global)
|
|
1488
|
-
Global$1.
|
|
1471
|
+
Global$1.add(instance);
|
|
1489
1472
|
return instance;
|
|
1490
1473
|
}
|
|
1491
1474
|
static get(arg1, arg2) {
|
|
1492
|
-
let instance;
|
|
1493
1475
|
const required = arg1 === undefined || arg1 === true;
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
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;
|
|
1501
1482
|
function callback(effect) {
|
|
1502
1483
|
try {
|
|
1503
1484
|
React__default["default"].useLayoutEffect(() => effect(instance), []);
|
|
@@ -1509,29 +1490,18 @@ class MVC extends Model {
|
|
|
1509
1490
|
effect(undefined);
|
|
1510
1491
|
}
|
|
1511
1492
|
}
|
|
1512
|
-
if (typeof arg1 === "string")
|
|
1513
|
-
return instance[arg1];
|
|
1514
|
-
if (typeof arg1 === "function" && instance)
|
|
1515
|
-
callback(arg1);
|
|
1516
|
-
else if (arg2)
|
|
1517
|
-
callback(arg2);
|
|
1518
|
-
return instance;
|
|
1519
1493
|
}
|
|
1520
1494
|
static tap(arg1, arg2) {
|
|
1521
|
-
|
|
1522
|
-
return typeof arg1 == "function"
|
|
1523
|
-
? useCompute(instance, arg1, arg2)
|
|
1524
|
-
: useSubscribe(instance, arg1);
|
|
1495
|
+
return useTap(this, arg1, arg2);
|
|
1525
1496
|
}
|
|
1526
1497
|
static use(a, b) {
|
|
1527
|
-
return
|
|
1498
|
+
return useModel(this, a, b);
|
|
1528
1499
|
}
|
|
1529
1500
|
static meta(arg1, arg2) {
|
|
1530
|
-
return
|
|
1531
|
-
? useCompute(this, arg1, arg2)
|
|
1532
|
-
: useSubscribe(this, arg1);
|
|
1501
|
+
return useTap(() => this, arg1, arg2);
|
|
1533
1502
|
}
|
|
1534
|
-
}
|
|
1503
|
+
}
|
|
1504
|
+
FindInstruction.set(MVC, getContextForGetInstruction);
|
|
1535
1505
|
|
|
1536
1506
|
const Oops$1 = issues({
|
|
1537
1507
|
BadProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
@@ -1565,8 +1535,17 @@ function useNewContext(include, assign) {
|
|
|
1565
1535
|
throw Oops.NoType();
|
|
1566
1536
|
return ambient.push();
|
|
1567
1537
|
}, []);
|
|
1568
|
-
function register(key,
|
|
1569
|
-
|
|
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);
|
|
1570
1549
|
if (assign)
|
|
1571
1550
|
assignWeak(instance, assign);
|
|
1572
1551
|
}
|
|
@@ -1638,12 +1617,7 @@ exports.Provider = Provider;
|
|
|
1638
1617
|
exports.add = add;
|
|
1639
1618
|
exports["default"] = MVC;
|
|
1640
1619
|
exports.get = get;
|
|
1641
|
-
exports.has = has;
|
|
1642
1620
|
exports.ref = ref;
|
|
1643
1621
|
exports.run = run;
|
|
1644
1622
|
exports.set = set;
|
|
1645
|
-
exports.
|
|
1646
|
-
exports.use = use$1;
|
|
1647
|
-
exports.useContext = useContext;
|
|
1648
|
-
exports.useNew = useNew;
|
|
1649
|
-
exports.useTap = useTap;
|
|
1623
|
+
exports.use = use;
|