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