@expressive/mvc 0.19.2 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +197 -283
- package/lib/index.esm.js +650 -810
- package/lib/index.js +650 -813
- package/package.json +1 -11
package/lib/index.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 this.on(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,326 @@ 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
|
+
const PARENTS = new WeakMap();
|
|
431
|
+
class Control {
|
|
432
|
+
constructor(subject, id = random()) {
|
|
433
|
+
this.subject = subject;
|
|
434
|
+
this.id = id;
|
|
435
|
+
this.frame = new Set();
|
|
436
|
+
this.followers = new Set();
|
|
437
|
+
this.observers = new Map([["", this.followers]]);
|
|
438
|
+
REGISTER.set(subject, this);
|
|
439
|
+
}
|
|
440
|
+
add(key) {
|
|
441
|
+
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
442
|
+
const instruction = INSTRUCTION.get(value);
|
|
443
|
+
if (typeof instruction == "function") {
|
|
444
|
+
INSTRUCTION.delete(value);
|
|
445
|
+
instruction(key, this);
|
|
446
|
+
}
|
|
447
|
+
else if (value instanceof Model)
|
|
448
|
+
setRecursive(this, key, value);
|
|
449
|
+
else if (typeof value != "function")
|
|
450
|
+
this.watch(key, { value });
|
|
451
|
+
}
|
|
452
|
+
watch(key, output) {
|
|
453
|
+
const { state } = this;
|
|
454
|
+
const { get, set, enumerable } = output;
|
|
455
|
+
const subs = new Set();
|
|
456
|
+
this.observers.set(key, subs);
|
|
404
457
|
if ("value" in output)
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
defineProperty(control.subject, key, {
|
|
458
|
+
state[key] = output.value;
|
|
459
|
+
defineProperty(this.subject, key, {
|
|
408
460
|
enumerable,
|
|
409
|
-
set:
|
|
461
|
+
set: set === false
|
|
410
462
|
? undefined
|
|
411
|
-
:
|
|
463
|
+
: this.ref(key, set),
|
|
412
464
|
get() {
|
|
413
|
-
const
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
465
|
+
const event = OBSERVER.get(this);
|
|
466
|
+
if (event)
|
|
467
|
+
subs.add(event);
|
|
468
|
+
const value = get ? get(this) : state[key];
|
|
469
|
+
return event && value instanceof Model
|
|
470
|
+
? watch(value, event)
|
|
471
|
+
: value;
|
|
417
472
|
}
|
|
418
473
|
});
|
|
474
|
+
}
|
|
475
|
+
ref(key, callback) {
|
|
476
|
+
const { state, subject } = this;
|
|
477
|
+
return (value) => {
|
|
478
|
+
if (value !== state[key])
|
|
479
|
+
switch (callback && callback.call(subject, value)) {
|
|
480
|
+
case undefined:
|
|
481
|
+
state[key] = value;
|
|
482
|
+
case true:
|
|
483
|
+
this.update(key);
|
|
484
|
+
}
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
update(key) {
|
|
488
|
+
const { frame } = this;
|
|
489
|
+
if (frame.has(key))
|
|
490
|
+
return;
|
|
491
|
+
if (!frame.size) {
|
|
492
|
+
this.latest = undefined;
|
|
493
|
+
requestUpdateFrame(() => {
|
|
494
|
+
this.latest = Array.from(frame);
|
|
495
|
+
this.followers.forEach(cb => {
|
|
496
|
+
const notify = cb(undefined, this);
|
|
497
|
+
if (notify)
|
|
498
|
+
requestUpdateFrame(notify);
|
|
499
|
+
});
|
|
500
|
+
frame.clear();
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
frame.add(key);
|
|
504
|
+
for (const k of ["", key]) {
|
|
505
|
+
const subs = this.observers.get(k);
|
|
506
|
+
subs && subs.forEach(cb => {
|
|
507
|
+
const notify = cb(key, this);
|
|
508
|
+
if (notify === null)
|
|
509
|
+
subs.delete(cb);
|
|
510
|
+
else if (notify)
|
|
511
|
+
requestUpdateFrame(notify);
|
|
512
|
+
});
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
addListener(fn) {
|
|
516
|
+
this.followers.add(fn);
|
|
517
|
+
return () => this.followers.delete(fn);
|
|
518
|
+
}
|
|
519
|
+
clear() {
|
|
520
|
+
this.observers.forEach(subs => {
|
|
521
|
+
subs.forEach(fn => {
|
|
522
|
+
const cb = fn(null, this);
|
|
523
|
+
cb && cb();
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
this.observers.clear();
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
Control.after = new Set();
|
|
530
|
+
Control.before = new Set();
|
|
531
|
+
Control.pending = new Set();
|
|
532
|
+
Control.for = control;
|
|
533
|
+
Control.apply = apply;
|
|
534
|
+
Control.watch = watch;
|
|
535
|
+
const PENDING_INIT = new WeakMap();
|
|
536
|
+
function control(subject, ready) {
|
|
537
|
+
const control = REGISTER.get(subject.is);
|
|
538
|
+
const onReady = typeof ready == "function" && ready;
|
|
539
|
+
if (!control.state && ready) {
|
|
540
|
+
let waiting = PENDING_INIT.get(control);
|
|
541
|
+
if (!waiting)
|
|
542
|
+
PENDING_INIT.set(control, waiting = new Set());
|
|
543
|
+
if (onReady) {
|
|
544
|
+
let callback;
|
|
545
|
+
waiting.add(() => callback = onReady(control));
|
|
546
|
+
return () => callback && callback();
|
|
547
|
+
}
|
|
548
|
+
control.state = {};
|
|
549
|
+
for (const key in control.subject)
|
|
550
|
+
control.add(key);
|
|
551
|
+
waiting.forEach(cb => cb());
|
|
552
|
+
}
|
|
553
|
+
return onReady ? onReady(control) : control;
|
|
554
|
+
}
|
|
555
|
+
function requestUpdateFrame(event) {
|
|
556
|
+
const { after, before, pending } = Control;
|
|
557
|
+
if (!pending.size)
|
|
558
|
+
setTimeout(() => {
|
|
559
|
+
before.forEach(x => x());
|
|
560
|
+
pending.forEach(notify => {
|
|
561
|
+
try {
|
|
562
|
+
notify();
|
|
563
|
+
}
|
|
564
|
+
catch (err) {
|
|
565
|
+
console.error(err);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
pending.clear();
|
|
569
|
+
after.forEach(x => x());
|
|
570
|
+
}, 0);
|
|
571
|
+
pending.add(event);
|
|
572
|
+
}
|
|
573
|
+
function setRecursive(on, key, value) {
|
|
574
|
+
const set = (next) => {
|
|
575
|
+
if (next instanceof value.constructor) {
|
|
576
|
+
on.state[key] = next;
|
|
577
|
+
parent(next, on.subject);
|
|
578
|
+
control(next, true);
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
throw Oops$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
582
|
+
};
|
|
583
|
+
on.watch(key, { set });
|
|
584
|
+
set(value);
|
|
585
|
+
}
|
|
586
|
+
function parent(child, register) {
|
|
587
|
+
if (!register)
|
|
588
|
+
return PARENTS.get(child);
|
|
589
|
+
PARENTS.set(child, register);
|
|
590
|
+
}
|
|
591
|
+
function watch(on, cb) {
|
|
592
|
+
if (!on.hasOwnProperty("is"))
|
|
593
|
+
on = defineProperty(create(on), "is", { value: on });
|
|
594
|
+
OBSERVER.set(on, cb);
|
|
595
|
+
return on;
|
|
596
|
+
}
|
|
597
|
+
function apply(instruction) {
|
|
598
|
+
const placeholder = Symbol("instruction");
|
|
599
|
+
INSTRUCTION.set(placeholder, (key, onto) => {
|
|
600
|
+
delete onto.subject[key];
|
|
601
|
+
const output = instruction.call(onto, key, onto);
|
|
602
|
+
if (output)
|
|
603
|
+
onto.watch(key, typeof output == "function" ? { get: output } : output);
|
|
419
604
|
});
|
|
420
605
|
return placeholder;
|
|
606
|
+
}
|
|
607
|
+
/** Random alphanumberic of length 6; will always start with a letter. */
|
|
608
|
+
function random() {
|
|
609
|
+
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
421
610
|
}
|
|
422
611
|
|
|
423
612
|
const Oops$4 = issues({
|
|
613
|
+
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
614
|
+
});
|
|
615
|
+
function run(task) {
|
|
616
|
+
return apply((key, control) => {
|
|
617
|
+
let pending = false;
|
|
618
|
+
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
619
|
+
if (pending)
|
|
620
|
+
return Promise.reject(Oops$4.DuplicatePending(key));
|
|
621
|
+
pending = true;
|
|
622
|
+
control.update(key);
|
|
623
|
+
try {
|
|
624
|
+
return yield mayRetry(() => (task.apply(control.subject, args)));
|
|
625
|
+
}
|
|
626
|
+
finally {
|
|
627
|
+
pending = false;
|
|
628
|
+
control.update(key);
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
control.state[key] = undefined;
|
|
632
|
+
defineProperty(invoke, "active", {
|
|
633
|
+
get: () => pending
|
|
634
|
+
});
|
|
635
|
+
return {
|
|
636
|
+
value: invoke,
|
|
637
|
+
set: false
|
|
638
|
+
};
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const Oops$3 = issues({
|
|
424
643
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
425
644
|
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}
|
|
645
|
+
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
646
|
+
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
647
|
+
AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
|
|
427
648
|
});
|
|
428
649
|
function get(arg0, arg1) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
let { subject } = this;
|
|
650
|
+
return apply((key, control) => {
|
|
651
|
+
let { subject } = control;
|
|
432
652
|
if (typeof arg0 == "symbol")
|
|
433
|
-
throw Oops$
|
|
653
|
+
throw Oops$3.PeerNotAllowed(subject, key);
|
|
434
654
|
let source = cb => cb(subject);
|
|
435
655
|
if (arg0 instanceof Model)
|
|
436
656
|
subject = arg0;
|
|
437
|
-
else if (Model.isTypeof(arg0))
|
|
438
|
-
|
|
657
|
+
else if (Model.isTypeof(arg0)) {
|
|
658
|
+
const hasParent = parent(subject);
|
|
659
|
+
if (!hasParent) {
|
|
660
|
+
if (arg1 === true)
|
|
661
|
+
throw Oops$3.Required(arg0, subject);
|
|
662
|
+
source = callback => Control.has(arg0, subject, got => {
|
|
663
|
+
if (got)
|
|
664
|
+
callback(got);
|
|
665
|
+
else if (arg1 !== false)
|
|
666
|
+
throw Oops$3.AmbientRequired(arg0, subject);
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
else if (!arg0 || hasParent instanceof arg0)
|
|
670
|
+
subject = hasParent;
|
|
671
|
+
else
|
|
672
|
+
throw Oops$3.Unexpected(arg0, subject, hasParent);
|
|
673
|
+
}
|
|
439
674
|
else if (typeof arg0 == "function")
|
|
440
675
|
arg1 = arg0.call(subject, key, subject);
|
|
441
676
|
return typeof arg1 == "function"
|
|
442
|
-
? computed(
|
|
443
|
-
: recursive(
|
|
677
|
+
? computed(control, key, source, arg1)
|
|
678
|
+
: recursive(control, key, source, arg1);
|
|
444
679
|
});
|
|
445
680
|
}
|
|
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
681
|
function recursive(parent, key, source, required) {
|
|
456
|
-
const getter = getRecursive(key, parent);
|
|
457
682
|
let waiting;
|
|
458
|
-
source
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
683
|
+
if (source)
|
|
684
|
+
source((got) => {
|
|
685
|
+
parent.state[key] = got;
|
|
686
|
+
if (waiting)
|
|
687
|
+
parent.update(key);
|
|
688
|
+
});
|
|
463
689
|
waiting = true;
|
|
464
|
-
return (
|
|
465
|
-
const value = parent.state
|
|
466
|
-
if (
|
|
467
|
-
|
|
468
|
-
|
|
690
|
+
return () => {
|
|
691
|
+
const value = parent.state[key];
|
|
692
|
+
if (value)
|
|
693
|
+
return value;
|
|
694
|
+
if (required !== false)
|
|
695
|
+
throw suspense(parent, key);
|
|
469
696
|
};
|
|
470
697
|
}
|
|
698
|
+
const ORDER = new WeakMap();
|
|
699
|
+
const PENDING = new Set();
|
|
700
|
+
let OFFSET = 0;
|
|
471
701
|
function computed(parent, key, source, setter) {
|
|
472
702
|
const { state } = parent;
|
|
473
|
-
let
|
|
703
|
+
let proxy;
|
|
474
704
|
let active;
|
|
475
705
|
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);
|
|
706
|
+
let reset;
|
|
483
707
|
function compute(initial) {
|
|
708
|
+
if (parent.frame.has(key))
|
|
709
|
+
return;
|
|
484
710
|
let next;
|
|
485
711
|
try {
|
|
486
|
-
next = setter.call(
|
|
712
|
+
next = setter.call(proxy, proxy);
|
|
487
713
|
}
|
|
488
714
|
catch (err) {
|
|
489
|
-
Oops$
|
|
715
|
+
Oops$3.Failed(parent.subject, key, initial).warn();
|
|
490
716
|
if (initial)
|
|
491
717
|
throw err;
|
|
492
718
|
console.error(err);
|
|
493
719
|
}
|
|
494
|
-
if (next !== state
|
|
495
|
-
state
|
|
720
|
+
if (next !== state[key]) {
|
|
721
|
+
state[key] = next;
|
|
496
722
|
if (!initial || isAsync)
|
|
497
723
|
parent.update(key);
|
|
498
724
|
}
|
|
499
725
|
}
|
|
500
726
|
function connect(model) {
|
|
501
|
-
|
|
727
|
+
if (reset)
|
|
728
|
+
reset();
|
|
729
|
+
let done;
|
|
730
|
+
reset = () => done = true;
|
|
731
|
+
proxy = watch(model, (_, control) => {
|
|
732
|
+
if (done)
|
|
733
|
+
return null;
|
|
502
734
|
if (control !== parent)
|
|
503
735
|
compute();
|
|
504
736
|
else
|
|
505
|
-
|
|
737
|
+
PENDING.add(compute);
|
|
506
738
|
});
|
|
507
|
-
local.watch.set(key, false);
|
|
508
739
|
try {
|
|
509
740
|
compute(true);
|
|
510
741
|
}
|
|
511
742
|
finally {
|
|
512
|
-
|
|
513
|
-
order.set(compute, order.size);
|
|
743
|
+
ORDER.set(compute, OFFSET++);
|
|
514
744
|
}
|
|
515
745
|
}
|
|
516
746
|
return () => {
|
|
@@ -519,297 +749,32 @@ function computed(parent, key, source, setter) {
|
|
|
519
749
|
source(connect);
|
|
520
750
|
isAsync = true;
|
|
521
751
|
}
|
|
522
|
-
if (!
|
|
523
|
-
parent
|
|
524
|
-
if (
|
|
752
|
+
if (!proxy)
|
|
753
|
+
throw suspense(parent, key);
|
|
754
|
+
if (PENDING.delete(compute))
|
|
525
755
|
compute();
|
|
526
|
-
return state
|
|
756
|
+
return state[key];
|
|
527
757
|
};
|
|
528
758
|
}
|
|
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) {
|
|
759
|
+
function flushComputed() {
|
|
760
|
+
while (PENDING.size) {
|
|
538
761
|
let compute;
|
|
539
|
-
for (const item of
|
|
540
|
-
if (!compute ||
|
|
762
|
+
for (const item of PENDING)
|
|
763
|
+
if (!compute || ORDER.get(item) < ORDER.get(compute))
|
|
541
764
|
compute = item;
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
if (!control.frame.has(key))
|
|
545
|
-
compute();
|
|
765
|
+
PENDING.delete(compute);
|
|
766
|
+
compute();
|
|
546
767
|
}
|
|
547
|
-
pending.clear();
|
|
548
|
-
}
|
|
549
|
-
function using(fn) {
|
|
550
|
-
return Object.assign(get.bind(fn), { using });
|
|
551
768
|
}
|
|
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
|
-
}
|
|
769
|
+
Control.before.add(flushComputed);
|
|
804
770
|
|
|
805
771
|
function ref(arg, mapper) {
|
|
806
|
-
return
|
|
772
|
+
return apply((key, source) => {
|
|
807
773
|
let value = {};
|
|
808
|
-
this.state.set(key, undefined);
|
|
809
774
|
if (typeof arg != "object")
|
|
810
|
-
value = createRef(
|
|
775
|
+
value = createRef(source, key, arg);
|
|
811
776
|
else
|
|
812
|
-
control(arg).state
|
|
777
|
+
for (const key in control(arg, true).state) {
|
|
813
778
|
defineProperty(value, key, mapper ? {
|
|
814
779
|
configurable: true,
|
|
815
780
|
get() {
|
|
@@ -818,28 +783,30 @@ function ref(arg, mapper) {
|
|
|
818
783
|
return out;
|
|
819
784
|
}
|
|
820
785
|
} : {
|
|
821
|
-
value: createRef(
|
|
786
|
+
value: createRef(source, key)
|
|
822
787
|
});
|
|
823
|
-
}
|
|
824
|
-
|
|
788
|
+
}
|
|
789
|
+
source.state[key] = undefined;
|
|
790
|
+
source.observers.set(key, new Set());
|
|
791
|
+
defineProperty(source.subject, key, { value });
|
|
825
792
|
});
|
|
826
793
|
}
|
|
827
794
|
function createRef(src, key, cb) {
|
|
828
795
|
const refObjectFunction = src.ref(key, cb && createValueEffect(cb));
|
|
829
796
|
defineProperty(refObjectFunction, "current", {
|
|
830
797
|
set: refObjectFunction,
|
|
831
|
-
get: () => src.state
|
|
798
|
+
get: () => src.state[key]
|
|
832
799
|
});
|
|
833
800
|
return refObjectFunction;
|
|
834
801
|
}
|
|
835
802
|
|
|
836
|
-
const Oops$
|
|
803
|
+
const Oops$2 = issues({
|
|
837
804
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
838
805
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
839
806
|
});
|
|
840
807
|
function set(value, argument) {
|
|
841
|
-
return
|
|
842
|
-
const { state, subject } =
|
|
808
|
+
return apply((key, control) => {
|
|
809
|
+
const { state, subject } = control;
|
|
843
810
|
if (typeof value == "function" || value instanceof Promise) {
|
|
844
811
|
const required = argument !== false;
|
|
845
812
|
let getter;
|
|
@@ -850,24 +817,24 @@ function set(value, argument) {
|
|
|
850
817
|
let pending;
|
|
851
818
|
let error;
|
|
852
819
|
if (value instanceof Promise) {
|
|
853
|
-
state
|
|
820
|
+
state[key] = undefined;
|
|
854
821
|
pending = value
|
|
855
822
|
.catch(err => error = err)
|
|
856
823
|
.then(val => {
|
|
857
|
-
state
|
|
824
|
+
state[key] = val;
|
|
858
825
|
return val;
|
|
859
826
|
})
|
|
860
827
|
.finally(() => {
|
|
861
828
|
pending = undefined;
|
|
862
|
-
|
|
829
|
+
control.update(key);
|
|
863
830
|
});
|
|
864
831
|
}
|
|
865
832
|
else
|
|
866
|
-
state
|
|
833
|
+
state[key] = value;
|
|
867
834
|
const suspend = () => {
|
|
868
835
|
if (required === false)
|
|
869
836
|
return undefined;
|
|
870
|
-
const issue = Oops$
|
|
837
|
+
const issue = Oops$2.NotReady(subject, key);
|
|
871
838
|
assign(pending, {
|
|
872
839
|
message: issue.message,
|
|
873
840
|
stack: issue.stack
|
|
@@ -879,12 +846,11 @@ function set(value, argument) {
|
|
|
879
846
|
throw error;
|
|
880
847
|
if (pending)
|
|
881
848
|
return suspend();
|
|
882
|
-
|
|
883
|
-
return state.get(key);
|
|
849
|
+
return state[key];
|
|
884
850
|
};
|
|
885
851
|
}
|
|
886
852
|
catch (err) {
|
|
887
|
-
Oops$
|
|
853
|
+
Oops$2.ComputeFailed(subject, key).warn();
|
|
888
854
|
throw err;
|
|
889
855
|
}
|
|
890
856
|
};
|
|
@@ -897,13 +863,13 @@ function set(value, argument) {
|
|
|
897
863
|
};
|
|
898
864
|
}
|
|
899
865
|
if (value !== undefined)
|
|
900
|
-
state
|
|
866
|
+
state[key] = value;
|
|
901
867
|
return {
|
|
902
868
|
get: () => {
|
|
903
|
-
if (state
|
|
904
|
-
return state
|
|
869
|
+
if (key in state)
|
|
870
|
+
return state[key];
|
|
905
871
|
else
|
|
906
|
-
|
|
872
|
+
throw suspense(control, key);
|
|
907
873
|
},
|
|
908
874
|
set: typeof argument == "function"
|
|
909
875
|
? createValueEffect(argument)
|
|
@@ -912,180 +878,27 @@ function set(value, argument) {
|
|
|
912
878
|
});
|
|
913
879
|
}
|
|
914
880
|
|
|
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({
|
|
881
|
+
const Oops$1 = issues({
|
|
1064
882
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1065
883
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
1066
884
|
});
|
|
1067
885
|
function use(input, argument) {
|
|
1068
|
-
return
|
|
1069
|
-
const { state, subject } =
|
|
886
|
+
return apply((key, source) => {
|
|
887
|
+
const { state, subject } = source;
|
|
1070
888
|
const required = argument !== false;
|
|
1071
889
|
let pending;
|
|
1072
890
|
let error;
|
|
1073
|
-
let get = (_local) => state.get(key);
|
|
1074
891
|
if (typeof input === "function") {
|
|
1075
892
|
if ("prototype" in input && input === input.prototype.constructor)
|
|
1076
893
|
input = new input();
|
|
1077
894
|
}
|
|
1078
895
|
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);
|
|
896
|
+
throw Oops$1.BadArgument(typeof input);
|
|
1082
897
|
const onUpdate = (next) => {
|
|
1083
|
-
state
|
|
898
|
+
state[key] = next;
|
|
1084
899
|
if (next) {
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
Parent.set(next, subject);
|
|
1088
|
-
control(next);
|
|
900
|
+
parent(next, subject);
|
|
901
|
+
control(next, true);
|
|
1089
902
|
}
|
|
1090
903
|
if (typeof argument == "function")
|
|
1091
904
|
argument(next);
|
|
@@ -1094,7 +907,7 @@ function use(input, argument) {
|
|
|
1094
907
|
const suspend = () => {
|
|
1095
908
|
if (required === false)
|
|
1096
909
|
return;
|
|
1097
|
-
const issue = Oops.NotReady(subject, key);
|
|
910
|
+
const issue = Oops$1.NotReady(subject, key);
|
|
1098
911
|
assign(pending, {
|
|
1099
912
|
message: issue.message,
|
|
1100
913
|
stack: issue.stack
|
|
@@ -1107,14 +920,14 @@ function use(input, argument) {
|
|
|
1107
920
|
input;
|
|
1108
921
|
if (output instanceof Promise) {
|
|
1109
922
|
pending = output
|
|
1110
|
-
.catch(err => error = err)
|
|
1111
923
|
.then(val => {
|
|
1112
924
|
onUpdate(val);
|
|
1113
925
|
return val;
|
|
1114
926
|
})
|
|
927
|
+
.catch(err => error = err)
|
|
1115
928
|
.finally(() => {
|
|
1116
929
|
pending = undefined;
|
|
1117
|
-
|
|
930
|
+
source.update(key);
|
|
1118
931
|
});
|
|
1119
932
|
return;
|
|
1120
933
|
}
|
|
@@ -1124,60 +937,29 @@ function use(input, argument) {
|
|
|
1124
937
|
initialize();
|
|
1125
938
|
return {
|
|
1126
939
|
set: onUpdate,
|
|
1127
|
-
get(
|
|
940
|
+
get() {
|
|
1128
941
|
if (pending)
|
|
1129
942
|
return suspend();
|
|
1130
943
|
if (error)
|
|
1131
944
|
throw error;
|
|
1132
|
-
if (!
|
|
945
|
+
if (!(key in state))
|
|
1133
946
|
initialize();
|
|
1134
947
|
if (pending)
|
|
1135
948
|
return suspend();
|
|
1136
|
-
return
|
|
949
|
+
return state[key];
|
|
1137
950
|
}
|
|
1138
951
|
};
|
|
1139
952
|
});
|
|
1140
953
|
}
|
|
1141
954
|
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1144
|
-
|
|
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
|
-
}
|
|
955
|
+
const Oops = issues({
|
|
956
|
+
MultipleExist: (name) => `Did find ${name} in context, but multiple were defined.`,
|
|
957
|
+
NewValue: (name) => `Provider already has already defined '${name}' but got new value. This is not yet supported.`
|
|
1170
958
|
});
|
|
1171
|
-
|
|
1172
|
-
CONTROL,
|
|
1173
|
-
LOCAL,
|
|
1174
|
-
STATE,
|
|
1175
|
-
UPDATE
|
|
1176
|
-
};
|
|
1177
|
-
|
|
1178
|
-
class Register {
|
|
959
|
+
class Context {
|
|
1179
960
|
constructor() {
|
|
1180
|
-
this.table = new
|
|
961
|
+
this.table = new WeakMap();
|
|
962
|
+
this.input = new Map();
|
|
1181
963
|
}
|
|
1182
964
|
has(T) {
|
|
1183
965
|
let key = this.table.get(T);
|
|
@@ -1188,9 +970,37 @@ class Register {
|
|
|
1188
970
|
return key;
|
|
1189
971
|
}
|
|
1190
972
|
get(Type) {
|
|
1191
|
-
|
|
973
|
+
const result = this[this.has(Type)];
|
|
974
|
+
if (result === null)
|
|
975
|
+
throw Oops.MultipleExist(Type);
|
|
976
|
+
return result;
|
|
1192
977
|
}
|
|
1193
|
-
|
|
978
|
+
include(inputs) {
|
|
979
|
+
const init = new Map();
|
|
980
|
+
for (const key in inputs) {
|
|
981
|
+
const input = inputs[key];
|
|
982
|
+
const exists = this.input.get(key);
|
|
983
|
+
if (exists)
|
|
984
|
+
if (exists !== input)
|
|
985
|
+
throw Oops.NewValue(key);
|
|
986
|
+
else
|
|
987
|
+
continue;
|
|
988
|
+
const instance = this.add(input);
|
|
989
|
+
this.input.set(key, input);
|
|
990
|
+
init.set(instance, true);
|
|
991
|
+
}
|
|
992
|
+
for (const [model] of init) {
|
|
993
|
+
const { state } = control(model, true);
|
|
994
|
+
Object.values(state).forEach(value => {
|
|
995
|
+
if (parent(value) === model) {
|
|
996
|
+
this.add(value, true);
|
|
997
|
+
init.set(value, false);
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
return init;
|
|
1002
|
+
}
|
|
1003
|
+
add(input, implicit) {
|
|
1194
1004
|
let writable = true;
|
|
1195
1005
|
let T;
|
|
1196
1006
|
let I;
|
|
@@ -1205,20 +1015,20 @@ class Register {
|
|
|
1205
1015
|
}
|
|
1206
1016
|
do {
|
|
1207
1017
|
const key = this.has(T);
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1018
|
+
const value = this.hasOwnProperty(key) ? null : I;
|
|
1019
|
+
if (value || I !== this[key] && !implicit)
|
|
1020
|
+
defineProperty(this, key, {
|
|
1021
|
+
configurable: true,
|
|
1022
|
+
value,
|
|
1023
|
+
writable
|
|
1024
|
+
});
|
|
1213
1025
|
T = getPrototypeOf(T);
|
|
1214
1026
|
} while (T !== Model);
|
|
1215
|
-
if (key !== undefined)
|
|
1216
|
-
this.register.set(key, input);
|
|
1217
1027
|
return I;
|
|
1218
1028
|
}
|
|
1219
1029
|
push() {
|
|
1220
1030
|
const next = create(this);
|
|
1221
|
-
next.
|
|
1031
|
+
next.input = new Map();
|
|
1222
1032
|
return next;
|
|
1223
1033
|
}
|
|
1224
1034
|
pop() {
|
|
@@ -1230,12 +1040,42 @@ class Register {
|
|
|
1230
1040
|
delete this[key];
|
|
1231
1041
|
}
|
|
1232
1042
|
for (const model of items)
|
|
1233
|
-
model.
|
|
1043
|
+
model.null();
|
|
1044
|
+
this.input.clear();
|
|
1234
1045
|
}
|
|
1235
1046
|
}
|
|
1236
1047
|
|
|
1237
|
-
const
|
|
1238
|
-
|
|
1048
|
+
const STATE = "__state";
|
|
1049
|
+
const UPDATE = "__update";
|
|
1050
|
+
const CONTROL = "__control";
|
|
1051
|
+
const PARENT = "__parent";
|
|
1052
|
+
defineProperties(Model.prototype, {
|
|
1053
|
+
[CONTROL]: {
|
|
1054
|
+
get() {
|
|
1055
|
+
return control(this);
|
|
1056
|
+
}
|
|
1057
|
+
},
|
|
1058
|
+
[STATE]: {
|
|
1059
|
+
get() {
|
|
1060
|
+
return Object.assign({}, control(this).state);
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
[UPDATE]: {
|
|
1064
|
+
get() {
|
|
1065
|
+
return control(this).latest;
|
|
1066
|
+
}
|
|
1067
|
+
},
|
|
1068
|
+
[PARENT]: {
|
|
1069
|
+
get() {
|
|
1070
|
+
return parent(this);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
});
|
|
1074
|
+
const Debug = {
|
|
1075
|
+
CONTROL,
|
|
1076
|
+
STATE,
|
|
1077
|
+
UPDATE,
|
|
1078
|
+
PARENT
|
|
1239
1079
|
};
|
|
1240
1080
|
|
|
1241
|
-
export { Control, Debug,
|
|
1081
|
+
export { Context, Control, Debug, Model, Model as default, get, issues, ref, run, set, use };
|