@expressive/mvc 0.19.2 → 0.21.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 +197 -283
- package/lib/index.esm.js +650 -810
- package/lib/index.js +650 -813
- package/package.json +1 -11
package/lib/index.js
CHANGED
|
@@ -2,10 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
/******************************************************************************
|
|
6
|
+
Copyright (c) Microsoft Corporation.
|
|
7
|
+
|
|
8
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
9
|
+
purpose with or without fee is hereby granted.
|
|
10
|
+
|
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
12
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
13
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
14
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
15
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
16
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
17
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
18
|
+
***************************************************************************** */
|
|
19
|
+
|
|
20
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
21
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
22
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
23
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
24
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
25
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
26
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
27
|
+
});
|
|
9
28
|
}
|
|
10
29
|
|
|
11
30
|
class Issue extends Error {
|
|
@@ -25,89 +44,27 @@ function issues(register) {
|
|
|
25
44
|
return Library;
|
|
26
45
|
}
|
|
27
46
|
|
|
28
|
-
const
|
|
29
|
-
class Subscriber {
|
|
30
|
-
constructor(parent, onUpdate) {
|
|
31
|
-
this.onUpdate = onUpdate;
|
|
32
|
-
this.active = false;
|
|
33
|
-
this.dependant = new Set();
|
|
34
|
-
this.watch = new Map();
|
|
35
|
-
if (!(parent instanceof Control))
|
|
36
|
-
parent = Control.for(parent);
|
|
37
|
-
const reset = () => this.latest = undefined;
|
|
38
|
-
const proxy = create(parent.subject);
|
|
39
|
-
REGISTER$1.set(proxy, this);
|
|
40
|
-
defineProperty(this, "proxy", {
|
|
41
|
-
configurable: true,
|
|
42
|
-
get() {
|
|
43
|
-
setTimeout(reset, 0);
|
|
44
|
-
return proxy;
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
this.parent = parent;
|
|
48
|
-
this.clear = parent.addListener(key => {
|
|
49
|
-
if (this.active)
|
|
50
|
-
this.notify(key);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
get using() {
|
|
54
|
-
return Array.from(this.watch.keys());
|
|
55
|
-
}
|
|
56
|
-
get(key, using) {
|
|
57
|
-
this.follow(key);
|
|
58
|
-
return using
|
|
59
|
-
? using(this)
|
|
60
|
-
: this.parent.state.get(key);
|
|
61
|
-
}
|
|
62
|
-
follow(key, value) {
|
|
63
|
-
if (value !== undefined)
|
|
64
|
-
this.watch.set(key, value);
|
|
65
|
-
else if (!this.watch.has(key))
|
|
66
|
-
this.watch.set(key, true);
|
|
67
|
-
}
|
|
68
|
-
commit() {
|
|
69
|
-
this.active = true;
|
|
70
|
-
this.dependant.forEach(x => x.commit());
|
|
71
|
-
}
|
|
72
|
-
release() {
|
|
73
|
-
this.clear();
|
|
74
|
-
this.dependant.forEach(x => x.release());
|
|
75
|
-
}
|
|
76
|
-
notify(key) {
|
|
77
|
-
const { parent, watch } = this;
|
|
78
|
-
const handler = watch.get(key);
|
|
79
|
-
if (!handler)
|
|
80
|
-
return;
|
|
81
|
-
if (typeof handler == "function")
|
|
82
|
-
handler();
|
|
83
|
-
const notify = this.onUpdate(key, parent);
|
|
84
|
-
if (notify) {
|
|
85
|
-
parent.waiting.add(update => {
|
|
86
|
-
this.latest = update.filter(k => watch.has(k));
|
|
87
|
-
});
|
|
88
|
-
parent.waiting.add(notify);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function subscriber(from) {
|
|
93
|
-
return REGISTER$1.get(from);
|
|
94
|
-
}
|
|
47
|
+
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
95
48
|
|
|
96
|
-
const Oops$
|
|
49
|
+
const Oops$9 = issues({
|
|
97
50
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
51
|
+
Destoryed: () => "Model is destroyed."
|
|
98
52
|
});
|
|
99
|
-
function
|
|
100
|
-
const error = Oops$
|
|
101
|
-
const promise = new Promise(resolve => {
|
|
102
|
-
const
|
|
103
|
-
|
|
53
|
+
function suspense(source, key) {
|
|
54
|
+
const error = Oops$9.NotReady(source.subject, key);
|
|
55
|
+
const promise = new Promise((resolve, reject) => {
|
|
56
|
+
const subs = source.observers.get(key);
|
|
57
|
+
const onUpdate = (key) => {
|
|
58
|
+
if (key)
|
|
104
59
|
return () => {
|
|
105
|
-
if (source.state
|
|
106
|
-
|
|
60
|
+
if (source.state[key] !== undefined) {
|
|
61
|
+
subs.delete(onUpdate);
|
|
107
62
|
resolve();
|
|
108
63
|
}
|
|
109
64
|
};
|
|
110
|
-
|
|
65
|
+
reject(Oops$9.Destoryed());
|
|
66
|
+
};
|
|
67
|
+
subs.add(onUpdate);
|
|
111
68
|
});
|
|
112
69
|
return assign(promise, {
|
|
113
70
|
toString: () => String(error),
|
|
@@ -137,11 +94,12 @@ function mayRetry(fn) {
|
|
|
137
94
|
return compute();
|
|
138
95
|
}
|
|
139
96
|
|
|
140
|
-
const Oops$
|
|
97
|
+
const Oops$8 = issues({
|
|
141
98
|
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
142
99
|
});
|
|
143
|
-
function createEffect(
|
|
144
|
-
return control(
|
|
100
|
+
function createEffect(source, callback) {
|
|
101
|
+
return control(source, self => {
|
|
102
|
+
let { subject } = self;
|
|
145
103
|
let unSet;
|
|
146
104
|
let busy = false;
|
|
147
105
|
function invoke() {
|
|
@@ -150,33 +108,23 @@ function createEffect(model, callback, keys) {
|
|
|
150
108
|
const output = mayRetry(() => {
|
|
151
109
|
if (typeof unSet == "function")
|
|
152
110
|
unSet();
|
|
153
|
-
unSet = callback.call(
|
|
111
|
+
unSet = callback.call(subject, subject);
|
|
154
112
|
if (unSet instanceof Promise)
|
|
155
113
|
unSet = undefined;
|
|
156
114
|
if (unSet && typeof unSet !== "function")
|
|
157
|
-
throw Oops$
|
|
115
|
+
throw Oops$8.BadCallback();
|
|
158
116
|
});
|
|
159
117
|
if (output instanceof Promise) {
|
|
160
118
|
output.finally(() => busy = false);
|
|
161
119
|
busy = true;
|
|
162
120
|
}
|
|
163
121
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
if (key === null) {
|
|
168
|
-
if (!keys.length)
|
|
169
|
-
invoke();
|
|
170
|
-
}
|
|
171
|
-
else if (keys.includes(key))
|
|
172
|
-
return invoke;
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
const sub = new Subscriber(controller, () => invoke);
|
|
176
|
-
model = sub.proxy;
|
|
122
|
+
let refresh;
|
|
123
|
+
subject = watch(subject, () => refresh);
|
|
124
|
+
self.followers.add(key => (key === null || refresh === null ? refresh : undefined));
|
|
177
125
|
invoke();
|
|
178
|
-
|
|
179
|
-
return () =>
|
|
126
|
+
refresh = invoke;
|
|
127
|
+
return () => refresh = null;
|
|
180
128
|
});
|
|
181
129
|
}
|
|
182
130
|
function createValueEffect(callback) {
|
|
@@ -192,162 +140,254 @@ function createValueEffect(callback) {
|
|
|
192
140
|
if (typeof out == "function")
|
|
193
141
|
unSet = out;
|
|
194
142
|
else
|
|
195
|
-
throw Oops$
|
|
143
|
+
throw Oops$8.BadCallback();
|
|
196
144
|
};
|
|
197
145
|
}
|
|
198
146
|
|
|
199
|
-
const Oops$
|
|
200
|
-
|
|
201
|
-
KeysExpected: (key) => `Key "${key}" was expected in current update.`,
|
|
202
|
-
StrictUpdate: () => `Expected update but none in progress.`,
|
|
203
|
-
StrictNoUpdate: () => `Update is not expected but one is in progress!`
|
|
147
|
+
const Oops$7 = issues({
|
|
148
|
+
KeysExpected: (key) => `Key "${key}" was expected in current update.`
|
|
204
149
|
});
|
|
205
|
-
function addEventListener(source,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
150
|
+
function addEventListener(source, select, callback, once) {
|
|
151
|
+
return control(source, self => {
|
|
152
|
+
const { subject } = self;
|
|
153
|
+
if (typeof select == "string")
|
|
154
|
+
select = [select];
|
|
155
|
+
if (select)
|
|
156
|
+
for (const key of select)
|
|
157
|
+
try {
|
|
158
|
+
void subject[key];
|
|
159
|
+
}
|
|
160
|
+
catch (e) {
|
|
161
|
+
// TODO: should this be caught?
|
|
162
|
+
}
|
|
163
|
+
const removeListener = self.addListener(key => {
|
|
164
|
+
if (key === null)
|
|
165
|
+
callback.call(subject, null);
|
|
166
|
+
else if (!select || select.includes(key)) {
|
|
167
|
+
if (once)
|
|
219
168
|
removeListener();
|
|
220
|
-
return
|
|
169
|
+
return () => callback.call(subject, self.latest);
|
|
221
170
|
}
|
|
222
171
|
});
|
|
223
172
|
return removeListener;
|
|
224
173
|
});
|
|
225
174
|
}
|
|
226
|
-
function awaitUpdate(source,
|
|
227
|
-
const single = typeof arg1 == "string";
|
|
228
|
-
const keys = typeof arg1 == "string" ? [arg1] :
|
|
229
|
-
typeof arg1 == "object" ? arg1 :
|
|
230
|
-
undefined;
|
|
175
|
+
function awaitUpdate(source, select, timeout) {
|
|
231
176
|
return new Promise((resolve, reject) => {
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
resolve(null);
|
|
244
|
-
return;
|
|
177
|
+
if (timeout === 0) {
|
|
178
|
+
const self = control(source, true);
|
|
179
|
+
if (!self.frame.size)
|
|
180
|
+
resolve(false);
|
|
181
|
+
else if (typeof select == "string" && !self.frame.has(select))
|
|
182
|
+
reject(Oops$7.KeysExpected(select));
|
|
183
|
+
else {
|
|
184
|
+
const remove = self.addListener(() => {
|
|
185
|
+
remove();
|
|
186
|
+
return () => resolve(self.latest);
|
|
187
|
+
});
|
|
245
188
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const remove = addEventListener(source, select, resolve, true);
|
|
192
|
+
if (timeout > 0)
|
|
193
|
+
setTimeout(() => {
|
|
194
|
+
remove();
|
|
195
|
+
resolve(false);
|
|
196
|
+
}, timeout);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const Oops$6 = issues({
|
|
202
|
+
NotFound: (name) => `Could not find ${name} in context.`
|
|
203
|
+
});
|
|
204
|
+
function get$1(arg1, arg2) {
|
|
205
|
+
return Control.get(this, (refresh, context) => {
|
|
206
|
+
let onUpdate;
|
|
207
|
+
let value;
|
|
208
|
+
if (typeof arg1 !== "function") {
|
|
209
|
+
context(got => {
|
|
210
|
+
if (got)
|
|
211
|
+
value = arg1 === undefined
|
|
212
|
+
? Control.watch(got, () => onUpdate)
|
|
213
|
+
: got;
|
|
214
|
+
else if (arg1 !== false)
|
|
215
|
+
throw Oops$6.NotFound(this);
|
|
216
|
+
});
|
|
217
|
+
return {
|
|
218
|
+
mount() {
|
|
219
|
+
onUpdate = refresh;
|
|
220
|
+
return () => onUpdate = null;
|
|
221
|
+
},
|
|
222
|
+
render: () => value
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
let compute = arg1;
|
|
226
|
+
let suspense;
|
|
227
|
+
let getValue;
|
|
228
|
+
let factory;
|
|
229
|
+
let proxy;
|
|
230
|
+
context(got => {
|
|
231
|
+
if (!got)
|
|
232
|
+
throw Oops$6.NotFound(this);
|
|
233
|
+
proxy = Control.watch(got, () => factory ? null : onUpdate);
|
|
234
|
+
getValue = () => compute.call(proxy, proxy, forceUpdate);
|
|
235
|
+
value = getValue();
|
|
236
|
+
function forceUpdate(action) {
|
|
237
|
+
if (typeof action == "function")
|
|
238
|
+
action = action();
|
|
239
|
+
if (getValue)
|
|
240
|
+
didUpdate(getValue());
|
|
241
|
+
else
|
|
242
|
+
refresh();
|
|
243
|
+
if (action)
|
|
244
|
+
return action.finally(refresh);
|
|
259
245
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
246
|
+
});
|
|
247
|
+
if (value === null) {
|
|
248
|
+
getValue = undefined;
|
|
249
|
+
onUpdate = null;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (typeof value == "function") {
|
|
253
|
+
const get = value;
|
|
254
|
+
Control.watch(proxy, () => onUpdate);
|
|
255
|
+
factory = true;
|
|
256
|
+
compute = () => get();
|
|
257
|
+
value = get();
|
|
258
|
+
}
|
|
259
|
+
const didUpdate = (got) => {
|
|
260
|
+
value = got;
|
|
261
|
+
if (suspense) {
|
|
262
|
+
suspense();
|
|
263
|
+
suspense = undefined;
|
|
263
264
|
}
|
|
264
265
|
else
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
266
|
+
refresh();
|
|
267
|
+
};
|
|
268
|
+
if (value instanceof Promise) {
|
|
269
|
+
onUpdate = null;
|
|
270
|
+
value.then(didUpdate);
|
|
271
|
+
value = undefined;
|
|
272
|
+
}
|
|
273
|
+
else
|
|
274
|
+
onUpdate = () => {
|
|
275
|
+
const next = getValue();
|
|
276
|
+
if (notEqual(value, next))
|
|
277
|
+
didUpdate(next);
|
|
278
|
+
};
|
|
279
|
+
return {
|
|
280
|
+
mount: () => () => {
|
|
281
|
+
onUpdate = null;
|
|
282
|
+
},
|
|
283
|
+
render: () => {
|
|
284
|
+
if (value !== undefined)
|
|
285
|
+
return value;
|
|
286
|
+
if (arg2)
|
|
287
|
+
throw new Promise(res => {
|
|
288
|
+
suspense = res;
|
|
289
|
+
});
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
/** Values are not equal for purposes of a refresh. */
|
|
296
|
+
const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
|
|
297
|
+
!Array.isArray(b) ||
|
|
298
|
+
a.length !== b.length ||
|
|
299
|
+
a.some((x, i) => x !== b[i])));
|
|
300
|
+
|
|
301
|
+
function use$1(arg1, arg2) {
|
|
302
|
+
const render = Control.use((refresh) => {
|
|
303
|
+
let onUpdate;
|
|
304
|
+
let applyProps = typeof arg1 === "object";
|
|
305
|
+
const instance = this.new();
|
|
306
|
+
const proxy = Control.watch(instance, () => onUpdate);
|
|
307
|
+
if (typeof arg1 == "function")
|
|
308
|
+
arg1(instance);
|
|
309
|
+
return {
|
|
310
|
+
instance,
|
|
311
|
+
mount() {
|
|
312
|
+
onUpdate = refresh;
|
|
313
|
+
return () => {
|
|
314
|
+
onUpdate = null;
|
|
315
|
+
instance.null();
|
|
316
|
+
};
|
|
317
|
+
},
|
|
318
|
+
render(props) {
|
|
319
|
+
if (applyProps) {
|
|
320
|
+
onUpdate = undefined;
|
|
321
|
+
applyProps = !!arg2;
|
|
322
|
+
for (const key in props)
|
|
323
|
+
if (instance.hasOwnProperty(key))
|
|
324
|
+
instance[key] = props[key];
|
|
325
|
+
instance.on(0).then(() => onUpdate = refresh);
|
|
276
326
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
setTimeout(() => timeout(`${arg2}ms`), arg2);
|
|
327
|
+
return proxy;
|
|
328
|
+
}
|
|
329
|
+
};
|
|
281
330
|
});
|
|
331
|
+
return render(arg1);
|
|
282
332
|
}
|
|
283
333
|
|
|
284
|
-
const Oops$5 = issues({
|
|
285
|
-
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`,
|
|
286
|
-
NoAdapter: (method) => `Can't call Model.${method} without an adapter.`
|
|
287
|
-
});
|
|
288
334
|
class Model {
|
|
289
335
|
constructor(id) {
|
|
290
|
-
new Control(this);
|
|
291
|
-
|
|
292
|
-
|
|
336
|
+
new Control(this, id);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Reference to `this` without a subscription.
|
|
340
|
+
* Use to obtain full reference from a destructure.
|
|
341
|
+
*/
|
|
342
|
+
get is() {
|
|
343
|
+
return this;
|
|
293
344
|
}
|
|
294
345
|
on(arg1, arg2, arg3) {
|
|
295
346
|
if (typeof arg1 == "function")
|
|
296
|
-
return createEffect(this
|
|
297
|
-
if (typeof
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
347
|
+
return createEffect(this, arg1);
|
|
348
|
+
if (typeof arg1 == "number") {
|
|
349
|
+
arg2 = arg1;
|
|
350
|
+
arg1 = undefined;
|
|
351
|
+
}
|
|
352
|
+
return typeof arg2 == "function"
|
|
353
|
+
? addEventListener(this, arg1, arg2, arg3)
|
|
354
|
+
: awaitUpdate(this, arg1, arg2);
|
|
301
355
|
}
|
|
302
356
|
get(arg1, arg2) {
|
|
303
|
-
const { state } = control(this);
|
|
304
|
-
|
|
357
|
+
const { state } = control(this, true);
|
|
358
|
+
function values() {
|
|
305
359
|
if (typeof arg1 == "string")
|
|
306
|
-
return state
|
|
360
|
+
return state[arg1];
|
|
361
|
+
if (!arg1)
|
|
362
|
+
return Object.assign({}, state);
|
|
307
363
|
const output = {};
|
|
308
|
-
for (const key of arg1
|
|
309
|
-
output[key] = state
|
|
364
|
+
for (const key of arg1)
|
|
365
|
+
output[key] = state[key];
|
|
310
366
|
return output;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
return this.on(arg1, () => arg2(extract()));
|
|
316
|
-
const timeout = typeof arg2 == "number" ? arg2 : undefined;
|
|
317
|
-
return this.on(arg1, timeout).then(extract);
|
|
367
|
+
}
|
|
368
|
+
return typeof arg2 == "function"
|
|
369
|
+
? this.on(arg1, () => arg2(values()))
|
|
370
|
+
: values();
|
|
318
371
|
}
|
|
319
372
|
set(arg1, arg2) {
|
|
320
|
-
const controller = control(this);
|
|
373
|
+
const controller = control(this, true);
|
|
321
374
|
const { state } = controller;
|
|
322
375
|
if (typeof arg1 == "string") {
|
|
323
376
|
controller.update(arg1);
|
|
324
|
-
if (1 in arguments)
|
|
325
|
-
|
|
326
|
-
state.set(arg1, arg2);
|
|
327
|
-
else if (arg1 in this) {
|
|
328
|
-
const method = this[arg1];
|
|
329
|
-
if (typeof method == "function")
|
|
330
|
-
method.call(this, arg2);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
377
|
+
if (1 in arguments && arg1 in state)
|
|
378
|
+
state[arg1] = arg2;
|
|
333
379
|
}
|
|
334
380
|
else if (typeof arg1 == "object")
|
|
335
|
-
for (const key in
|
|
336
|
-
if (
|
|
337
|
-
state
|
|
381
|
+
for (const key in state)
|
|
382
|
+
if (key in arg1 && (!arg2 || arg2.includes(key))) {
|
|
383
|
+
state[key] = arg1[key];
|
|
338
384
|
controller.update(key);
|
|
339
385
|
}
|
|
340
|
-
return
|
|
341
|
-
then: (callback) => {
|
|
342
|
-
if (!callback)
|
|
343
|
-
throw Oops$5.NoChaining();
|
|
344
|
-
controller.waiting.add(callback);
|
|
345
|
-
}
|
|
346
|
-
};
|
|
386
|
+
return this.on(0);
|
|
347
387
|
}
|
|
348
388
|
/** Mark this instance for garbage collection. */
|
|
349
|
-
|
|
350
|
-
control(this).clear();
|
|
389
|
+
null() {
|
|
390
|
+
control(this, true).clear();
|
|
351
391
|
}
|
|
352
392
|
/**
|
|
353
393
|
* Creates a new instance of this controller.
|
|
@@ -358,18 +398,9 @@ class Model {
|
|
|
358
398
|
*/
|
|
359
399
|
static new(...args) {
|
|
360
400
|
const instance = new this(...args);
|
|
361
|
-
control(instance);
|
|
401
|
+
control(instance, true);
|
|
362
402
|
return instance;
|
|
363
403
|
}
|
|
364
|
-
static find() {
|
|
365
|
-
throw Oops$5.NoAdapter("find");
|
|
366
|
-
}
|
|
367
|
-
static get() {
|
|
368
|
-
throw Oops$5.NoAdapter("get");
|
|
369
|
-
}
|
|
370
|
-
static use() {
|
|
371
|
-
throw Oops$5.NoAdapter("use");
|
|
372
|
-
}
|
|
373
404
|
/**
|
|
374
405
|
* Static equivalent of `x instanceof this`.
|
|
375
406
|
*
|
|
@@ -380,10 +411,12 @@ class Model {
|
|
|
380
411
|
maybe.prototype instanceof this);
|
|
381
412
|
}
|
|
382
413
|
}
|
|
414
|
+
Model.get = get$1;
|
|
415
|
+
Model.use = use$1;
|
|
383
416
|
defineProperty(Model.prototype, "toString", {
|
|
384
417
|
configurable: true,
|
|
385
418
|
value() {
|
|
386
|
-
return `${this.constructor.name}-${this.id}`;
|
|
419
|
+
return `${this.constructor.name}-${control(this).id}`;
|
|
387
420
|
}
|
|
388
421
|
});
|
|
389
422
|
defineProperty(Model, "toString", {
|
|
@@ -392,129 +425,326 @@ defineProperty(Model, "toString", {
|
|
|
392
425
|
}
|
|
393
426
|
});
|
|
394
427
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
428
|
+
const Oops$5 = issues({
|
|
429
|
+
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
430
|
+
});
|
|
431
|
+
const INSTRUCTION = new Map();
|
|
432
|
+
const REGISTER = new WeakMap();
|
|
433
|
+
const OBSERVER = new WeakMap();
|
|
434
|
+
const PARENTS = new WeakMap();
|
|
435
|
+
class Control {
|
|
436
|
+
constructor(subject, id = random()) {
|
|
437
|
+
this.subject = subject;
|
|
438
|
+
this.id = id;
|
|
439
|
+
this.frame = new Set();
|
|
440
|
+
this.followers = new Set();
|
|
441
|
+
this.observers = new Map([["", this.followers]]);
|
|
442
|
+
REGISTER.set(subject, this);
|
|
443
|
+
}
|
|
444
|
+
add(key) {
|
|
445
|
+
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
446
|
+
const instruction = INSTRUCTION.get(value);
|
|
447
|
+
if (typeof instruction == "function") {
|
|
448
|
+
INSTRUCTION.delete(value);
|
|
449
|
+
instruction(key, this);
|
|
450
|
+
}
|
|
451
|
+
else if (value instanceof Model)
|
|
452
|
+
setRecursive(this, key, value);
|
|
453
|
+
else if (typeof value != "function")
|
|
454
|
+
this.watch(key, { value });
|
|
455
|
+
}
|
|
456
|
+
watch(key, output) {
|
|
457
|
+
const { state } = this;
|
|
458
|
+
const { get, set, enumerable } = output;
|
|
459
|
+
const subs = new Set();
|
|
460
|
+
this.observers.set(key, subs);
|
|
408
461
|
if ("value" in output)
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
defineProperty(control.subject, key, {
|
|
462
|
+
state[key] = output.value;
|
|
463
|
+
defineProperty(this.subject, key, {
|
|
412
464
|
enumerable,
|
|
413
|
-
set:
|
|
465
|
+
set: set === false
|
|
414
466
|
? undefined
|
|
415
|
-
:
|
|
467
|
+
: this.ref(key, set),
|
|
416
468
|
get() {
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
469
|
+
const event = OBSERVER.get(this);
|
|
470
|
+
if (event)
|
|
471
|
+
subs.add(event);
|
|
472
|
+
const value = get ? get(this) : state[key];
|
|
473
|
+
return event && value instanceof Model
|
|
474
|
+
? watch(value, event)
|
|
475
|
+
: value;
|
|
421
476
|
}
|
|
422
477
|
});
|
|
478
|
+
}
|
|
479
|
+
ref(key, callback) {
|
|
480
|
+
const { state, subject } = this;
|
|
481
|
+
return (value) => {
|
|
482
|
+
if (value !== state[key])
|
|
483
|
+
switch (callback && callback.call(subject, value)) {
|
|
484
|
+
case undefined:
|
|
485
|
+
state[key] = value;
|
|
486
|
+
case true:
|
|
487
|
+
this.update(key);
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
update(key) {
|
|
492
|
+
const { frame } = this;
|
|
493
|
+
if (frame.has(key))
|
|
494
|
+
return;
|
|
495
|
+
if (!frame.size) {
|
|
496
|
+
this.latest = undefined;
|
|
497
|
+
requestUpdateFrame(() => {
|
|
498
|
+
this.latest = Array.from(frame);
|
|
499
|
+
this.followers.forEach(cb => {
|
|
500
|
+
const notify = cb(undefined, this);
|
|
501
|
+
if (notify)
|
|
502
|
+
requestUpdateFrame(notify);
|
|
503
|
+
});
|
|
504
|
+
frame.clear();
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
frame.add(key);
|
|
508
|
+
for (const k of ["", key]) {
|
|
509
|
+
const subs = this.observers.get(k);
|
|
510
|
+
subs && subs.forEach(cb => {
|
|
511
|
+
const notify = cb(key, this);
|
|
512
|
+
if (notify === null)
|
|
513
|
+
subs.delete(cb);
|
|
514
|
+
else if (notify)
|
|
515
|
+
requestUpdateFrame(notify);
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
addListener(fn) {
|
|
520
|
+
this.followers.add(fn);
|
|
521
|
+
return () => this.followers.delete(fn);
|
|
522
|
+
}
|
|
523
|
+
clear() {
|
|
524
|
+
this.observers.forEach(subs => {
|
|
525
|
+
subs.forEach(fn => {
|
|
526
|
+
const cb = fn(null, this);
|
|
527
|
+
cb && cb();
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
this.observers.clear();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
Control.after = new Set();
|
|
534
|
+
Control.before = new Set();
|
|
535
|
+
Control.pending = new Set();
|
|
536
|
+
Control.for = control;
|
|
537
|
+
Control.apply = apply;
|
|
538
|
+
Control.watch = watch;
|
|
539
|
+
const PENDING_INIT = new WeakMap();
|
|
540
|
+
function control(subject, ready) {
|
|
541
|
+
const control = REGISTER.get(subject.is);
|
|
542
|
+
const onReady = typeof ready == "function" && ready;
|
|
543
|
+
if (!control.state && ready) {
|
|
544
|
+
let waiting = PENDING_INIT.get(control);
|
|
545
|
+
if (!waiting)
|
|
546
|
+
PENDING_INIT.set(control, waiting = new Set());
|
|
547
|
+
if (onReady) {
|
|
548
|
+
let callback;
|
|
549
|
+
waiting.add(() => callback = onReady(control));
|
|
550
|
+
return () => callback && callback();
|
|
551
|
+
}
|
|
552
|
+
control.state = {};
|
|
553
|
+
for (const key in control.subject)
|
|
554
|
+
control.add(key);
|
|
555
|
+
waiting.forEach(cb => cb());
|
|
556
|
+
}
|
|
557
|
+
return onReady ? onReady(control) : control;
|
|
558
|
+
}
|
|
559
|
+
function requestUpdateFrame(event) {
|
|
560
|
+
const { after, before, pending } = Control;
|
|
561
|
+
if (!pending.size)
|
|
562
|
+
setTimeout(() => {
|
|
563
|
+
before.forEach(x => x());
|
|
564
|
+
pending.forEach(notify => {
|
|
565
|
+
try {
|
|
566
|
+
notify();
|
|
567
|
+
}
|
|
568
|
+
catch (err) {
|
|
569
|
+
console.error(err);
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
pending.clear();
|
|
573
|
+
after.forEach(x => x());
|
|
574
|
+
}, 0);
|
|
575
|
+
pending.add(event);
|
|
576
|
+
}
|
|
577
|
+
function setRecursive(on, key, value) {
|
|
578
|
+
const set = (next) => {
|
|
579
|
+
if (next instanceof value.constructor) {
|
|
580
|
+
on.state[key] = next;
|
|
581
|
+
parent(next, on.subject);
|
|
582
|
+
control(next, true);
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
throw Oops$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
586
|
+
};
|
|
587
|
+
on.watch(key, { set });
|
|
588
|
+
set(value);
|
|
589
|
+
}
|
|
590
|
+
function parent(child, register) {
|
|
591
|
+
if (!register)
|
|
592
|
+
return PARENTS.get(child);
|
|
593
|
+
PARENTS.set(child, register);
|
|
594
|
+
}
|
|
595
|
+
function watch(on, cb) {
|
|
596
|
+
if (!on.hasOwnProperty("is"))
|
|
597
|
+
on = defineProperty(create(on), "is", { value: on });
|
|
598
|
+
OBSERVER.set(on, cb);
|
|
599
|
+
return on;
|
|
600
|
+
}
|
|
601
|
+
function apply(instruction) {
|
|
602
|
+
const placeholder = Symbol("instruction");
|
|
603
|
+
INSTRUCTION.set(placeholder, (key, onto) => {
|
|
604
|
+
delete onto.subject[key];
|
|
605
|
+
const output = instruction.call(onto, key, onto);
|
|
606
|
+
if (output)
|
|
607
|
+
onto.watch(key, typeof output == "function" ? { get: output } : output);
|
|
423
608
|
});
|
|
424
609
|
return placeholder;
|
|
610
|
+
}
|
|
611
|
+
/** Random alphanumberic of length 6; will always start with a letter. */
|
|
612
|
+
function random() {
|
|
613
|
+
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
425
614
|
}
|
|
426
615
|
|
|
427
616
|
const Oops$4 = issues({
|
|
617
|
+
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
618
|
+
});
|
|
619
|
+
function run(task) {
|
|
620
|
+
return apply((key, control) => {
|
|
621
|
+
let pending = false;
|
|
622
|
+
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
623
|
+
if (pending)
|
|
624
|
+
return Promise.reject(Oops$4.DuplicatePending(key));
|
|
625
|
+
pending = true;
|
|
626
|
+
control.update(key);
|
|
627
|
+
try {
|
|
628
|
+
return yield mayRetry(() => (task.apply(control.subject, args)));
|
|
629
|
+
}
|
|
630
|
+
finally {
|
|
631
|
+
pending = false;
|
|
632
|
+
control.update(key);
|
|
633
|
+
}
|
|
634
|
+
});
|
|
635
|
+
control.state[key] = undefined;
|
|
636
|
+
defineProperty(invoke, "active", {
|
|
637
|
+
get: () => pending
|
|
638
|
+
});
|
|
639
|
+
return {
|
|
640
|
+
value: invoke,
|
|
641
|
+
set: false
|
|
642
|
+
};
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
const Oops$3 = issues({
|
|
428
647
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
429
648
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
430
|
-
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}
|
|
649
|
+
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
650
|
+
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
651
|
+
AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
|
|
431
652
|
});
|
|
432
653
|
function get(arg0, arg1) {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
let { subject } = this;
|
|
654
|
+
return apply((key, control) => {
|
|
655
|
+
let { subject } = control;
|
|
436
656
|
if (typeof arg0 == "symbol")
|
|
437
|
-
throw Oops$
|
|
657
|
+
throw Oops$3.PeerNotAllowed(subject, key);
|
|
438
658
|
let source = cb => cb(subject);
|
|
439
659
|
if (arg0 instanceof Model)
|
|
440
660
|
subject = arg0;
|
|
441
|
-
else if (Model.isTypeof(arg0))
|
|
442
|
-
|
|
661
|
+
else if (Model.isTypeof(arg0)) {
|
|
662
|
+
const hasParent = parent(subject);
|
|
663
|
+
if (!hasParent) {
|
|
664
|
+
if (arg1 === true)
|
|
665
|
+
throw Oops$3.Required(arg0, subject);
|
|
666
|
+
source = callback => Control.has(arg0, subject, got => {
|
|
667
|
+
if (got)
|
|
668
|
+
callback(got);
|
|
669
|
+
else if (arg1 !== false)
|
|
670
|
+
throw Oops$3.AmbientRequired(arg0, subject);
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
else if (!arg0 || hasParent instanceof arg0)
|
|
674
|
+
subject = hasParent;
|
|
675
|
+
else
|
|
676
|
+
throw Oops$3.Unexpected(arg0, subject, hasParent);
|
|
677
|
+
}
|
|
443
678
|
else if (typeof arg0 == "function")
|
|
444
679
|
arg1 = arg0.call(subject, key, subject);
|
|
445
680
|
return typeof arg1 == "function"
|
|
446
|
-
? computed(
|
|
447
|
-
: recursive(
|
|
681
|
+
? computed(control, key, source, arg1)
|
|
682
|
+
: recursive(control, key, source, arg1);
|
|
448
683
|
});
|
|
449
684
|
}
|
|
450
|
-
function getParentForGetInstruction(type, relativeTo, required) {
|
|
451
|
-
const item = getParent(relativeTo, type);
|
|
452
|
-
return callback => {
|
|
453
|
-
if (item)
|
|
454
|
-
callback(item);
|
|
455
|
-
else if (required)
|
|
456
|
-
throw Oops$4.Required(type, relativeTo.constructor);
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
685
|
function recursive(parent, key, source, required) {
|
|
460
|
-
const getter = getRecursive(key, parent);
|
|
461
686
|
let waiting;
|
|
462
|
-
source
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
687
|
+
if (source)
|
|
688
|
+
source((got) => {
|
|
689
|
+
parent.state[key] = got;
|
|
690
|
+
if (waiting)
|
|
691
|
+
parent.update(key);
|
|
692
|
+
});
|
|
467
693
|
waiting = true;
|
|
468
|
-
return (
|
|
469
|
-
const value = parent.state
|
|
470
|
-
if (
|
|
471
|
-
|
|
472
|
-
|
|
694
|
+
return () => {
|
|
695
|
+
const value = parent.state[key];
|
|
696
|
+
if (value)
|
|
697
|
+
return value;
|
|
698
|
+
if (required !== false)
|
|
699
|
+
throw suspense(parent, key);
|
|
473
700
|
};
|
|
474
701
|
}
|
|
702
|
+
const ORDER = new WeakMap();
|
|
703
|
+
const PENDING = new Set();
|
|
704
|
+
let OFFSET = 0;
|
|
475
705
|
function computed(parent, key, source, setter) {
|
|
476
706
|
const { state } = parent;
|
|
477
|
-
let
|
|
707
|
+
let proxy;
|
|
478
708
|
let active;
|
|
479
709
|
let isAsync;
|
|
480
|
-
let
|
|
481
|
-
let pending = KEYS.get(parent);
|
|
482
|
-
if (!order)
|
|
483
|
-
ORDER.set(parent, order = new Map());
|
|
484
|
-
if (!pending)
|
|
485
|
-
KEYS.set(parent, pending = new Set());
|
|
486
|
-
INFO.set(compute, key);
|
|
710
|
+
let reset;
|
|
487
711
|
function compute(initial) {
|
|
712
|
+
if (parent.frame.has(key))
|
|
713
|
+
return;
|
|
488
714
|
let next;
|
|
489
715
|
try {
|
|
490
|
-
next = setter.call(
|
|
716
|
+
next = setter.call(proxy, proxy);
|
|
491
717
|
}
|
|
492
718
|
catch (err) {
|
|
493
|
-
Oops$
|
|
719
|
+
Oops$3.Failed(parent.subject, key, initial).warn();
|
|
494
720
|
if (initial)
|
|
495
721
|
throw err;
|
|
496
722
|
console.error(err);
|
|
497
723
|
}
|
|
498
|
-
if (next !== state
|
|
499
|
-
state
|
|
724
|
+
if (next !== state[key]) {
|
|
725
|
+
state[key] = next;
|
|
500
726
|
if (!initial || isAsync)
|
|
501
727
|
parent.update(key);
|
|
502
728
|
}
|
|
503
729
|
}
|
|
504
730
|
function connect(model) {
|
|
505
|
-
|
|
731
|
+
if (reset)
|
|
732
|
+
reset();
|
|
733
|
+
let done;
|
|
734
|
+
reset = () => done = true;
|
|
735
|
+
proxy = watch(model, (_, control) => {
|
|
736
|
+
if (done)
|
|
737
|
+
return null;
|
|
506
738
|
if (control !== parent)
|
|
507
739
|
compute();
|
|
508
740
|
else
|
|
509
|
-
|
|
741
|
+
PENDING.add(compute);
|
|
510
742
|
});
|
|
511
|
-
local.watch.set(key, false);
|
|
512
743
|
try {
|
|
513
744
|
compute(true);
|
|
514
745
|
}
|
|
515
746
|
finally {
|
|
516
|
-
|
|
517
|
-
order.set(compute, order.size);
|
|
747
|
+
ORDER.set(compute, OFFSET++);
|
|
518
748
|
}
|
|
519
749
|
}
|
|
520
750
|
return () => {
|
|
@@ -523,297 +753,32 @@ function computed(parent, key, source, setter) {
|
|
|
523
753
|
source(connect);
|
|
524
754
|
isAsync = true;
|
|
525
755
|
}
|
|
526
|
-
if (!
|
|
527
|
-
parent
|
|
528
|
-
if (
|
|
756
|
+
if (!proxy)
|
|
757
|
+
throw suspense(parent, key);
|
|
758
|
+
if (PENDING.delete(compute))
|
|
529
759
|
compute();
|
|
530
|
-
return state
|
|
760
|
+
return state[key];
|
|
531
761
|
};
|
|
532
762
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
const ORDER = new WeakMap();
|
|
536
|
-
function flushComputed(control) {
|
|
537
|
-
const pending = KEYS.get(control);
|
|
538
|
-
if (!pending || !pending.size)
|
|
539
|
-
return;
|
|
540
|
-
const priority = ORDER.get(control);
|
|
541
|
-
while (pending.size) {
|
|
763
|
+
function flushComputed() {
|
|
764
|
+
while (PENDING.size) {
|
|
542
765
|
let compute;
|
|
543
|
-
for (const item of
|
|
544
|
-
if (!compute ||
|
|
766
|
+
for (const item of PENDING)
|
|
767
|
+
if (!compute || ORDER.get(item) < ORDER.get(compute))
|
|
545
768
|
compute = item;
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (!control.frame.has(key))
|
|
549
|
-
compute();
|
|
769
|
+
PENDING.delete(compute);
|
|
770
|
+
compute();
|
|
550
771
|
}
|
|
551
|
-
pending.clear();
|
|
552
|
-
}
|
|
553
|
-
function using(fn) {
|
|
554
|
-
return Object.assign(get.bind(fn), { using });
|
|
555
772
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
const REGISTER = new WeakMap();
|
|
559
|
-
const PENDING = new Map();
|
|
560
|
-
class Control {
|
|
561
|
-
constructor(subject) {
|
|
562
|
-
this.subject = subject;
|
|
563
|
-
this.frame = new Set();
|
|
564
|
-
this.waiting = new Set();
|
|
565
|
-
this.followers = new Set();
|
|
566
|
-
REGISTER.set(subject, this);
|
|
567
|
-
}
|
|
568
|
-
watch(key) {
|
|
569
|
-
const { subject, state } = this;
|
|
570
|
-
const { value } = getOwnPropertyDescriptor(subject, key);
|
|
571
|
-
if (typeof value == "function")
|
|
572
|
-
return;
|
|
573
|
-
if (typeof value == "symbol") {
|
|
574
|
-
const instruction = PENDING.get(value);
|
|
575
|
-
if (instruction) {
|
|
576
|
-
delete subject[key];
|
|
577
|
-
PENDING.delete(value);
|
|
578
|
-
instruction(this, key);
|
|
579
|
-
}
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
state.set(key, value);
|
|
583
|
-
if (value instanceof Model) {
|
|
584
|
-
setRecursive(this, key, value);
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
defineProperty(subject, key, {
|
|
588
|
-
enumerable: false,
|
|
589
|
-
set: this.ref(key),
|
|
590
|
-
get() {
|
|
591
|
-
const local = subscriber(this);
|
|
592
|
-
return local
|
|
593
|
-
? local.get(key)
|
|
594
|
-
: state.get(key);
|
|
595
|
-
}
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
/** Throw suspense which resolves when key is set. */
|
|
599
|
-
waitFor(key) {
|
|
600
|
-
throw suspend(this, key);
|
|
601
|
-
}
|
|
602
|
-
addListener(listener) {
|
|
603
|
-
this.followers.add(listener);
|
|
604
|
-
return () => {
|
|
605
|
-
this.followers.delete(listener);
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
ref(key, handler) {
|
|
609
|
-
const { subject, state } = this;
|
|
610
|
-
return (value) => {
|
|
611
|
-
if (state.get(key) == value)
|
|
612
|
-
return;
|
|
613
|
-
if (handler)
|
|
614
|
-
switch (handler.call(subject, value)) {
|
|
615
|
-
case true:
|
|
616
|
-
this.update(key);
|
|
617
|
-
case false:
|
|
618
|
-
return;
|
|
619
|
-
}
|
|
620
|
-
state.set(key, value);
|
|
621
|
-
this.update(key);
|
|
622
|
-
};
|
|
623
|
-
}
|
|
624
|
-
update(key) {
|
|
625
|
-
const { followers, frame, waiting } = this;
|
|
626
|
-
if (frame.has(key))
|
|
627
|
-
return;
|
|
628
|
-
else if (!frame.size)
|
|
629
|
-
setTimeout(() => {
|
|
630
|
-
flushComputed(this);
|
|
631
|
-
const keys = this.latest = Array.from(frame);
|
|
632
|
-
setTimeout(() => this.latest = undefined, 0);
|
|
633
|
-
frame.clear();
|
|
634
|
-
for (const notify of waiting)
|
|
635
|
-
try {
|
|
636
|
-
waiting.delete(notify);
|
|
637
|
-
notify(keys);
|
|
638
|
-
}
|
|
639
|
-
catch (err) {
|
|
640
|
-
console.error(err);
|
|
641
|
-
}
|
|
642
|
-
}, 0);
|
|
643
|
-
frame.add(key);
|
|
644
|
-
for (const callback of followers) {
|
|
645
|
-
const event = callback(key, this);
|
|
646
|
-
if (typeof event == "function")
|
|
647
|
-
waiting.add(event);
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
clear() {
|
|
651
|
-
const listeners = [...this.followers];
|
|
652
|
-
this.followers.clear();
|
|
653
|
-
listeners.forEach(x => x(null, this));
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
Control.get = controller;
|
|
657
|
-
Control.for = control;
|
|
658
|
-
function controller(from) {
|
|
659
|
-
if ("is" in from)
|
|
660
|
-
from = from.is;
|
|
661
|
-
return REGISTER.get(from);
|
|
662
|
-
}
|
|
663
|
-
function control(subject, cb) {
|
|
664
|
-
const control = controller(subject) || new Control(subject);
|
|
665
|
-
if (!control.state) {
|
|
666
|
-
const { waiting } = control;
|
|
667
|
-
if (cb) {
|
|
668
|
-
let callback;
|
|
669
|
-
waiting.add(() => {
|
|
670
|
-
callback = cb(control);
|
|
671
|
-
});
|
|
672
|
-
return () => {
|
|
673
|
-
if (callback)
|
|
674
|
-
callback();
|
|
675
|
-
};
|
|
676
|
-
}
|
|
677
|
-
control.state = new Map();
|
|
678
|
-
for (const key in subject)
|
|
679
|
-
control.watch(key);
|
|
680
|
-
control.waiting = new Set();
|
|
681
|
-
for (const cb of waiting)
|
|
682
|
-
cb([]);
|
|
683
|
-
}
|
|
684
|
-
return cb ? cb(control) : control;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
const Parent = new WeakMap();
|
|
688
|
-
const Oops$3 = issues({
|
|
689
|
-
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
690
|
-
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
691
|
-
});
|
|
692
|
-
function getParent(from, type) {
|
|
693
|
-
const value = Parent.get(from);
|
|
694
|
-
if (value && type && !(value instanceof type))
|
|
695
|
-
throw Oops$3.Unexpected(type, from, value);
|
|
696
|
-
return value;
|
|
697
|
-
}
|
|
698
|
-
function getRecursive(key, from) {
|
|
699
|
-
const context = new WeakMap();
|
|
700
|
-
const { state } = from;
|
|
701
|
-
return (local) => {
|
|
702
|
-
if (!context.has(local)) {
|
|
703
|
-
let reset;
|
|
704
|
-
const init = () => {
|
|
705
|
-
if (reset)
|
|
706
|
-
reset();
|
|
707
|
-
const value = state.get(key);
|
|
708
|
-
if (value && controller(value)) {
|
|
709
|
-
const child = new Subscriber(value, local.onUpdate);
|
|
710
|
-
if (local.active)
|
|
711
|
-
child.commit();
|
|
712
|
-
local.dependant.add(child);
|
|
713
|
-
context.set(local, child.proxy);
|
|
714
|
-
reset = () => {
|
|
715
|
-
child.release();
|
|
716
|
-
local.dependant.delete(child);
|
|
717
|
-
context.set(local, undefined);
|
|
718
|
-
reset = undefined;
|
|
719
|
-
};
|
|
720
|
-
}
|
|
721
|
-
};
|
|
722
|
-
local.follow(key, init);
|
|
723
|
-
init();
|
|
724
|
-
}
|
|
725
|
-
return context.get(local);
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
function setRecursive(controller, key, initial) {
|
|
729
|
-
const { state, subject } = controller;
|
|
730
|
-
const Type = initial.constructor;
|
|
731
|
-
let get;
|
|
732
|
-
const onUpdate = (next) => {
|
|
733
|
-
state.set(key, next);
|
|
734
|
-
if (!(next instanceof Type))
|
|
735
|
-
throw Oops$3.BadAssignment(`${subject}.${key}`, Type, String(next));
|
|
736
|
-
const getter = getRecursive(key, controller);
|
|
737
|
-
get = (local) => local ? getter(local) : state.get(key);
|
|
738
|
-
Parent.set(next, subject);
|
|
739
|
-
control(next);
|
|
740
|
-
return true;
|
|
741
|
-
};
|
|
742
|
-
onUpdate(initial);
|
|
743
|
-
defineProperty(subject, key, {
|
|
744
|
-
set: controller.ref(key, onUpdate),
|
|
745
|
-
get() {
|
|
746
|
-
const local = subscriber(this);
|
|
747
|
-
if (local)
|
|
748
|
-
local.follow(key);
|
|
749
|
-
return get(local);
|
|
750
|
-
}
|
|
751
|
-
});
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
/******************************************************************************
|
|
755
|
-
Copyright (c) Microsoft Corporation.
|
|
756
|
-
|
|
757
|
-
Permission to use, copy, modify, and/or distribute this software for any
|
|
758
|
-
purpose with or without fee is hereby granted.
|
|
759
|
-
|
|
760
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
761
|
-
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
762
|
-
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
763
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
764
|
-
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
765
|
-
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
766
|
-
PERFORMANCE OF THIS SOFTWARE.
|
|
767
|
-
***************************************************************************** */
|
|
768
|
-
|
|
769
|
-
function __awaiter(thisArg, _arguments, P, generator) {
|
|
770
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
771
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
772
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
773
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
774
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
775
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
776
|
-
});
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
const Oops$2 = issues({
|
|
780
|
-
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
781
|
-
});
|
|
782
|
-
function run(task) {
|
|
783
|
-
return add(function run(key) {
|
|
784
|
-
let pending = false;
|
|
785
|
-
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
786
|
-
if (pending)
|
|
787
|
-
return Promise.reject(Oops$2.DuplicatePending(key));
|
|
788
|
-
pending = true;
|
|
789
|
-
this.update(key);
|
|
790
|
-
try {
|
|
791
|
-
return yield mayRetry(() => (task.apply(this.subject, args)));
|
|
792
|
-
}
|
|
793
|
-
finally {
|
|
794
|
-
pending = false;
|
|
795
|
-
this.update(key);
|
|
796
|
-
}
|
|
797
|
-
});
|
|
798
|
-
this.state.set(key, undefined);
|
|
799
|
-
defineProperty(invoke, "active", {
|
|
800
|
-
get: () => pending
|
|
801
|
-
});
|
|
802
|
-
return {
|
|
803
|
-
value: invoke,
|
|
804
|
-
set: false
|
|
805
|
-
};
|
|
806
|
-
});
|
|
807
|
-
}
|
|
773
|
+
Control.before.add(flushComputed);
|
|
808
774
|
|
|
809
775
|
function ref(arg, mapper) {
|
|
810
|
-
return
|
|
776
|
+
return apply((key, source) => {
|
|
811
777
|
let value = {};
|
|
812
|
-
this.state.set(key, undefined);
|
|
813
778
|
if (typeof arg != "object")
|
|
814
|
-
value = createRef(
|
|
779
|
+
value = createRef(source, key, arg);
|
|
815
780
|
else
|
|
816
|
-
control(arg).state
|
|
781
|
+
for (const key in control(arg, true).state) {
|
|
817
782
|
defineProperty(value, key, mapper ? {
|
|
818
783
|
configurable: true,
|
|
819
784
|
get() {
|
|
@@ -822,28 +787,30 @@ function ref(arg, mapper) {
|
|
|
822
787
|
return out;
|
|
823
788
|
}
|
|
824
789
|
} : {
|
|
825
|
-
value: createRef(
|
|
790
|
+
value: createRef(source, key)
|
|
826
791
|
});
|
|
827
|
-
}
|
|
828
|
-
|
|
792
|
+
}
|
|
793
|
+
source.state[key] = undefined;
|
|
794
|
+
source.observers.set(key, new Set());
|
|
795
|
+
defineProperty(source.subject, key, { value });
|
|
829
796
|
});
|
|
830
797
|
}
|
|
831
798
|
function createRef(src, key, cb) {
|
|
832
799
|
const refObjectFunction = src.ref(key, cb && createValueEffect(cb));
|
|
833
800
|
defineProperty(refObjectFunction, "current", {
|
|
834
801
|
set: refObjectFunction,
|
|
835
|
-
get: () => src.state
|
|
802
|
+
get: () => src.state[key]
|
|
836
803
|
});
|
|
837
804
|
return refObjectFunction;
|
|
838
805
|
}
|
|
839
806
|
|
|
840
|
-
const Oops$
|
|
807
|
+
const Oops$2 = issues({
|
|
841
808
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
842
809
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
843
810
|
});
|
|
844
811
|
function set(value, argument) {
|
|
845
|
-
return
|
|
846
|
-
const { state, subject } =
|
|
812
|
+
return apply((key, control) => {
|
|
813
|
+
const { state, subject } = control;
|
|
847
814
|
if (typeof value == "function" || value instanceof Promise) {
|
|
848
815
|
const required = argument !== false;
|
|
849
816
|
let getter;
|
|
@@ -854,24 +821,24 @@ function set(value, argument) {
|
|
|
854
821
|
let pending;
|
|
855
822
|
let error;
|
|
856
823
|
if (value instanceof Promise) {
|
|
857
|
-
state
|
|
824
|
+
state[key] = undefined;
|
|
858
825
|
pending = value
|
|
859
826
|
.catch(err => error = err)
|
|
860
827
|
.then(val => {
|
|
861
|
-
state
|
|
828
|
+
state[key] = val;
|
|
862
829
|
return val;
|
|
863
830
|
})
|
|
864
831
|
.finally(() => {
|
|
865
832
|
pending = undefined;
|
|
866
|
-
|
|
833
|
+
control.update(key);
|
|
867
834
|
});
|
|
868
835
|
}
|
|
869
836
|
else
|
|
870
|
-
state
|
|
837
|
+
state[key] = value;
|
|
871
838
|
const suspend = () => {
|
|
872
839
|
if (required === false)
|
|
873
840
|
return undefined;
|
|
874
|
-
const issue = Oops$
|
|
841
|
+
const issue = Oops$2.NotReady(subject, key);
|
|
875
842
|
assign(pending, {
|
|
876
843
|
message: issue.message,
|
|
877
844
|
stack: issue.stack
|
|
@@ -883,12 +850,11 @@ function set(value, argument) {
|
|
|
883
850
|
throw error;
|
|
884
851
|
if (pending)
|
|
885
852
|
return suspend();
|
|
886
|
-
|
|
887
|
-
return state.get(key);
|
|
853
|
+
return state[key];
|
|
888
854
|
};
|
|
889
855
|
}
|
|
890
856
|
catch (err) {
|
|
891
|
-
Oops$
|
|
857
|
+
Oops$2.ComputeFailed(subject, key).warn();
|
|
892
858
|
throw err;
|
|
893
859
|
}
|
|
894
860
|
};
|
|
@@ -901,13 +867,13 @@ function set(value, argument) {
|
|
|
901
867
|
};
|
|
902
868
|
}
|
|
903
869
|
if (value !== undefined)
|
|
904
|
-
state
|
|
870
|
+
state[key] = value;
|
|
905
871
|
return {
|
|
906
872
|
get: () => {
|
|
907
|
-
if (state
|
|
908
|
-
return state
|
|
873
|
+
if (key in state)
|
|
874
|
+
return state[key];
|
|
909
875
|
else
|
|
910
|
-
|
|
876
|
+
throw suspense(control, key);
|
|
911
877
|
},
|
|
912
878
|
set: typeof argument == "function"
|
|
913
879
|
? createValueEffect(argument)
|
|
@@ -916,180 +882,27 @@ function set(value, argument) {
|
|
|
916
882
|
});
|
|
917
883
|
}
|
|
918
884
|
|
|
919
|
-
const
|
|
920
|
-
function keyed(control, property, initial) {
|
|
921
|
-
const init = createProxy(emit, watch);
|
|
922
|
-
const frozen = new Set();
|
|
923
|
-
const context = new Map();
|
|
924
|
-
const users = new Map();
|
|
925
|
-
const watched = new WeakMap();
|
|
926
|
-
const update = new Set();
|
|
927
|
-
let managed = init(initial);
|
|
928
|
-
function watch(on, key) {
|
|
929
|
-
const include = watched.get(on);
|
|
930
|
-
if (include)
|
|
931
|
-
include.add(key);
|
|
932
|
-
}
|
|
933
|
-
function emit(key) {
|
|
934
|
-
control.update(property);
|
|
935
|
-
control.waiting.add(() => frozen.clear());
|
|
936
|
-
update.forEach(notify => notify(key));
|
|
937
|
-
}
|
|
938
|
-
function subscribe(local) {
|
|
939
|
-
const proxy = create(managed);
|
|
940
|
-
let watch = users.get(local);
|
|
941
|
-
if (!watch) {
|
|
942
|
-
const using = watch = new Set();
|
|
943
|
-
users.set(local, using);
|
|
944
|
-
function onEvent(key) {
|
|
945
|
-
if (frozen.has(local))
|
|
946
|
-
return;
|
|
947
|
-
if (key === ANY || using.has(key) || using.has(ANY)) {
|
|
948
|
-
const refresh = local.onUpdate(property, control);
|
|
949
|
-
if (refresh) {
|
|
950
|
-
frozen.add(local);
|
|
951
|
-
refresh();
|
|
952
|
-
}
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
local.follow(property, false);
|
|
956
|
-
local.dependant.add({
|
|
957
|
-
commit() {
|
|
958
|
-
if (using.size === 0)
|
|
959
|
-
using.add(ANY);
|
|
960
|
-
update.add(onEvent);
|
|
961
|
-
},
|
|
962
|
-
release() {
|
|
963
|
-
update.delete(onEvent);
|
|
964
|
-
}
|
|
965
|
-
});
|
|
966
|
-
}
|
|
967
|
-
watched.set(proxy, watch);
|
|
968
|
-
context.set(local, proxy);
|
|
969
|
-
return proxy;
|
|
970
|
-
}
|
|
971
|
-
control.addListener(key => {
|
|
972
|
-
if (key === null) {
|
|
973
|
-
update.clear();
|
|
974
|
-
context.clear();
|
|
975
|
-
}
|
|
976
|
-
});
|
|
977
|
-
return {
|
|
978
|
-
value: initial,
|
|
979
|
-
get(local) {
|
|
980
|
-
return local ?
|
|
981
|
-
context.get(local) || subscribe(local) :
|
|
982
|
-
managed;
|
|
983
|
-
},
|
|
984
|
-
set(next) {
|
|
985
|
-
control.state.set(property, next);
|
|
986
|
-
managed = init(next);
|
|
987
|
-
context.clear();
|
|
988
|
-
emit(ANY);
|
|
989
|
-
}
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
function createProxy(emit, watch) {
|
|
993
|
-
return (from) => {
|
|
994
|
-
const proxy = create(from);
|
|
995
|
-
assign(proxy, {
|
|
996
|
-
from,
|
|
997
|
-
delete(key) {
|
|
998
|
-
// TODO: this commit's fix needs tests.
|
|
999
|
-
// Was not cause by coverage.
|
|
1000
|
-
const out = from.delete(key);
|
|
1001
|
-
emit(key);
|
|
1002
|
-
return out;
|
|
1003
|
-
},
|
|
1004
|
-
clear() {
|
|
1005
|
-
from.clear();
|
|
1006
|
-
emit(ANY);
|
|
1007
|
-
},
|
|
1008
|
-
has(key) {
|
|
1009
|
-
watch(this, key);
|
|
1010
|
-
return from.has(key);
|
|
1011
|
-
},
|
|
1012
|
-
keys() {
|
|
1013
|
-
watch(this, ANY);
|
|
1014
|
-
return from.keys();
|
|
1015
|
-
},
|
|
1016
|
-
values() {
|
|
1017
|
-
watch(this, ANY);
|
|
1018
|
-
return from.values();
|
|
1019
|
-
},
|
|
1020
|
-
entries() {
|
|
1021
|
-
watch(this, ANY);
|
|
1022
|
-
return from.entries();
|
|
1023
|
-
},
|
|
1024
|
-
forEach(callbackfn, thisArg) {
|
|
1025
|
-
const acc = [];
|
|
1026
|
-
from.forEach((a, b, c) => {
|
|
1027
|
-
const result = callbackfn.call(thisArg, a, b, c);
|
|
1028
|
-
if (result !== undefined)
|
|
1029
|
-
acc.push(result);
|
|
1030
|
-
});
|
|
1031
|
-
watch(this, ANY);
|
|
1032
|
-
return acc;
|
|
1033
|
-
},
|
|
1034
|
-
[Symbol.iterator]() {
|
|
1035
|
-
watch(this, ANY);
|
|
1036
|
-
return from[Symbol.iterator]();
|
|
1037
|
-
},
|
|
1038
|
-
}, from instanceof Set
|
|
1039
|
-
? {
|
|
1040
|
-
add(key) {
|
|
1041
|
-
from.add(key);
|
|
1042
|
-
emit(key);
|
|
1043
|
-
return this;
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
: {
|
|
1047
|
-
get(key) {
|
|
1048
|
-
watch(this, ANY);
|
|
1049
|
-
return from.get(key);
|
|
1050
|
-
},
|
|
1051
|
-
set(key, value) {
|
|
1052
|
-
from.set(key, value);
|
|
1053
|
-
emit(key);
|
|
1054
|
-
return this;
|
|
1055
|
-
}
|
|
1056
|
-
});
|
|
1057
|
-
defineProperty(proxy, "size", {
|
|
1058
|
-
get() {
|
|
1059
|
-
watch(this, ANY);
|
|
1060
|
-
return from.size;
|
|
1061
|
-
}
|
|
1062
|
-
});
|
|
1063
|
-
return proxy;
|
|
1064
|
-
};
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
const Oops = issues({
|
|
885
|
+
const Oops$1 = issues({
|
|
1068
886
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1069
887
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
1070
888
|
});
|
|
1071
889
|
function use(input, argument) {
|
|
1072
|
-
return
|
|
1073
|
-
const { state, subject } =
|
|
890
|
+
return apply((key, source) => {
|
|
891
|
+
const { state, subject } = source;
|
|
1074
892
|
const required = argument !== false;
|
|
1075
893
|
let pending;
|
|
1076
894
|
let error;
|
|
1077
|
-
let get = (_local) => state.get(key);
|
|
1078
895
|
if (typeof input === "function") {
|
|
1079
896
|
if ("prototype" in input && input === input.prototype.constructor)
|
|
1080
897
|
input = new input();
|
|
1081
898
|
}
|
|
1082
899
|
else if (input && typeof input !== "object")
|
|
1083
|
-
throw Oops.BadArgument(typeof input);
|
|
1084
|
-
if (input instanceof Map || input instanceof Set)
|
|
1085
|
-
return keyed(this, key, input);
|
|
900
|
+
throw Oops$1.BadArgument(typeof input);
|
|
1086
901
|
const onUpdate = (next) => {
|
|
1087
|
-
state
|
|
902
|
+
state[key] = next;
|
|
1088
903
|
if (next) {
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
Parent.set(next, subject);
|
|
1092
|
-
control(next);
|
|
904
|
+
parent(next, subject);
|
|
905
|
+
control(next, true);
|
|
1093
906
|
}
|
|
1094
907
|
if (typeof argument == "function")
|
|
1095
908
|
argument(next);
|
|
@@ -1098,7 +911,7 @@ function use(input, argument) {
|
|
|
1098
911
|
const suspend = () => {
|
|
1099
912
|
if (required === false)
|
|
1100
913
|
return;
|
|
1101
|
-
const issue = Oops.NotReady(subject, key);
|
|
914
|
+
const issue = Oops$1.NotReady(subject, key);
|
|
1102
915
|
assign(pending, {
|
|
1103
916
|
message: issue.message,
|
|
1104
917
|
stack: issue.stack
|
|
@@ -1111,14 +924,14 @@ function use(input, argument) {
|
|
|
1111
924
|
input;
|
|
1112
925
|
if (output instanceof Promise) {
|
|
1113
926
|
pending = output
|
|
1114
|
-
.catch(err => error = err)
|
|
1115
927
|
.then(val => {
|
|
1116
928
|
onUpdate(val);
|
|
1117
929
|
return val;
|
|
1118
930
|
})
|
|
931
|
+
.catch(err => error = err)
|
|
1119
932
|
.finally(() => {
|
|
1120
933
|
pending = undefined;
|
|
1121
|
-
|
|
934
|
+
source.update(key);
|
|
1122
935
|
});
|
|
1123
936
|
return;
|
|
1124
937
|
}
|
|
@@ -1128,60 +941,29 @@ function use(input, argument) {
|
|
|
1128
941
|
initialize();
|
|
1129
942
|
return {
|
|
1130
943
|
set: onUpdate,
|
|
1131
|
-
get(
|
|
944
|
+
get() {
|
|
1132
945
|
if (pending)
|
|
1133
946
|
return suspend();
|
|
1134
947
|
if (error)
|
|
1135
948
|
throw error;
|
|
1136
|
-
if (!
|
|
949
|
+
if (!(key in state))
|
|
1137
950
|
initialize();
|
|
1138
951
|
if (pending)
|
|
1139
952
|
return suspend();
|
|
1140
|
-
return
|
|
953
|
+
return state[key];
|
|
1141
954
|
}
|
|
1142
955
|
};
|
|
1143
956
|
});
|
|
1144
957
|
}
|
|
1145
958
|
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
const CONTROL = "__control";
|
|
1150
|
-
defineProperties(Model.prototype, {
|
|
1151
|
-
[CONTROL]: {
|
|
1152
|
-
get() {
|
|
1153
|
-
return controller(this);
|
|
1154
|
-
}
|
|
1155
|
-
},
|
|
1156
|
-
[LOCAL]: {
|
|
1157
|
-
get() {
|
|
1158
|
-
return subscriber(this);
|
|
1159
|
-
}
|
|
1160
|
-
},
|
|
1161
|
-
[STATE]: {
|
|
1162
|
-
get() {
|
|
1163
|
-
const { state } = controller(this);
|
|
1164
|
-
const output = {};
|
|
1165
|
-
state.forEach((value, key) => output[key] = value);
|
|
1166
|
-
return output;
|
|
1167
|
-
}
|
|
1168
|
-
},
|
|
1169
|
-
[UPDATE]: {
|
|
1170
|
-
get() {
|
|
1171
|
-
return (subscriber(this) || controller(this)).latest;
|
|
1172
|
-
}
|
|
1173
|
-
}
|
|
959
|
+
const Oops = issues({
|
|
960
|
+
MultipleExist: (name) => `Did find ${name} in context, but multiple were defined.`,
|
|
961
|
+
NewValue: (name) => `Provider already has already defined '${name}' but got new value. This is not yet supported.`
|
|
1174
962
|
});
|
|
1175
|
-
|
|
1176
|
-
CONTROL,
|
|
1177
|
-
LOCAL,
|
|
1178
|
-
STATE,
|
|
1179
|
-
UPDATE
|
|
1180
|
-
};
|
|
1181
|
-
|
|
1182
|
-
class Register {
|
|
963
|
+
class Context {
|
|
1183
964
|
constructor() {
|
|
1184
|
-
this.table = new
|
|
965
|
+
this.table = new WeakMap();
|
|
966
|
+
this.input = new Map();
|
|
1185
967
|
}
|
|
1186
968
|
has(T) {
|
|
1187
969
|
let key = this.table.get(T);
|
|
@@ -1192,9 +974,37 @@ class Register {
|
|
|
1192
974
|
return key;
|
|
1193
975
|
}
|
|
1194
976
|
get(Type) {
|
|
1195
|
-
|
|
977
|
+
const result = this[this.has(Type)];
|
|
978
|
+
if (result === null)
|
|
979
|
+
throw Oops.MultipleExist(Type);
|
|
980
|
+
return result;
|
|
1196
981
|
}
|
|
1197
|
-
|
|
982
|
+
include(inputs) {
|
|
983
|
+
const init = new Map();
|
|
984
|
+
for (const key in inputs) {
|
|
985
|
+
const input = inputs[key];
|
|
986
|
+
const exists = this.input.get(key);
|
|
987
|
+
if (exists)
|
|
988
|
+
if (exists !== input)
|
|
989
|
+
throw Oops.NewValue(key);
|
|
990
|
+
else
|
|
991
|
+
continue;
|
|
992
|
+
const instance = this.add(input);
|
|
993
|
+
this.input.set(key, input);
|
|
994
|
+
init.set(instance, true);
|
|
995
|
+
}
|
|
996
|
+
for (const [model] of init) {
|
|
997
|
+
const { state } = control(model, true);
|
|
998
|
+
Object.values(state).forEach(value => {
|
|
999
|
+
if (parent(value) === model) {
|
|
1000
|
+
this.add(value, true);
|
|
1001
|
+
init.set(value, false);
|
|
1002
|
+
}
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
return init;
|
|
1006
|
+
}
|
|
1007
|
+
add(input, implicit) {
|
|
1198
1008
|
let writable = true;
|
|
1199
1009
|
let T;
|
|
1200
1010
|
let I;
|
|
@@ -1209,20 +1019,20 @@ class Register {
|
|
|
1209
1019
|
}
|
|
1210
1020
|
do {
|
|
1211
1021
|
const key = this.has(T);
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1022
|
+
const value = this.hasOwnProperty(key) ? null : I;
|
|
1023
|
+
if (value || I !== this[key] && !implicit)
|
|
1024
|
+
defineProperty(this, key, {
|
|
1025
|
+
configurable: true,
|
|
1026
|
+
value,
|
|
1027
|
+
writable
|
|
1028
|
+
});
|
|
1217
1029
|
T = getPrototypeOf(T);
|
|
1218
1030
|
} while (T !== Model);
|
|
1219
|
-
if (key !== undefined)
|
|
1220
|
-
this.register.set(key, input);
|
|
1221
1031
|
return I;
|
|
1222
1032
|
}
|
|
1223
1033
|
push() {
|
|
1224
1034
|
const next = create(this);
|
|
1225
|
-
next.
|
|
1035
|
+
next.input = new Map();
|
|
1226
1036
|
return next;
|
|
1227
1037
|
}
|
|
1228
1038
|
pop() {
|
|
@@ -1234,21 +1044,48 @@ class Register {
|
|
|
1234
1044
|
delete this[key];
|
|
1235
1045
|
}
|
|
1236
1046
|
for (const model of items)
|
|
1237
|
-
model.
|
|
1047
|
+
model.null();
|
|
1048
|
+
this.input.clear();
|
|
1238
1049
|
}
|
|
1239
1050
|
}
|
|
1240
1051
|
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1052
|
+
const STATE = "__state";
|
|
1053
|
+
const UPDATE = "__update";
|
|
1054
|
+
const CONTROL = "__control";
|
|
1055
|
+
const PARENT = "__parent";
|
|
1056
|
+
defineProperties(Model.prototype, {
|
|
1057
|
+
[CONTROL]: {
|
|
1058
|
+
get() {
|
|
1059
|
+
return control(this);
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
[STATE]: {
|
|
1063
|
+
get() {
|
|
1064
|
+
return Object.assign({}, control(this).state);
|
|
1065
|
+
}
|
|
1066
|
+
},
|
|
1067
|
+
[UPDATE]: {
|
|
1068
|
+
get() {
|
|
1069
|
+
return control(this).latest;
|
|
1070
|
+
}
|
|
1071
|
+
},
|
|
1072
|
+
[PARENT]: {
|
|
1073
|
+
get() {
|
|
1074
|
+
return parent(this);
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
const Debug = {
|
|
1079
|
+
CONTROL,
|
|
1080
|
+
STATE,
|
|
1081
|
+
UPDATE,
|
|
1082
|
+
PARENT
|
|
1243
1083
|
};
|
|
1244
1084
|
|
|
1085
|
+
exports.Context = Context;
|
|
1245
1086
|
exports.Control = Control;
|
|
1246
1087
|
exports.Debug = Debug;
|
|
1247
|
-
exports.Internal = Internal;
|
|
1248
1088
|
exports.Model = Model;
|
|
1249
|
-
exports.Register = Register;
|
|
1250
|
-
exports.Subscriber = Subscriber;
|
|
1251
|
-
exports.add = add;
|
|
1252
1089
|
exports["default"] = Model;
|
|
1253
1090
|
exports.get = get;
|
|
1254
1091
|
exports.issues = issues;
|