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