@expressive/mvc 0.32.0 → 0.34.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 +122 -160
- package/lib/index.esm.js +413 -675
- package/lib/index.js +413 -675
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -27,619 +27,378 @@ function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
27
27
|
});
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
constructor() {
|
|
32
|
-
super(...arguments);
|
|
33
|
-
// drop first line (error factory) in stack trace.
|
|
34
|
-
this.stack = this.stack.replace(/\n.+/, "");
|
|
35
|
-
}
|
|
36
|
-
warn() {
|
|
37
|
-
console.warn(this.message);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function issues(register) {
|
|
41
|
-
const Library = {};
|
|
42
|
-
for (const name in register)
|
|
43
|
-
Library[name] = (...args) => new Issue(register[name].apply(null, args));
|
|
44
|
-
return Library;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const { assign, create, defineProperties, defineProperty, entries, keys, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
48
|
-
|
|
49
|
-
const Oops$8 = issues({
|
|
50
|
-
NotFound: (name) => `Could not find ${name} in context.`
|
|
51
|
-
});
|
|
52
|
-
function get$1(argument) {
|
|
53
|
-
return Control.get((dispatch, context) => {
|
|
54
|
-
const refresh = () => dispatch(x => x + 1);
|
|
55
|
-
let onUpdate;
|
|
56
|
-
let value;
|
|
57
|
-
if (typeof argument !== "function") {
|
|
58
|
-
const got = context.get(this);
|
|
59
|
-
if (got)
|
|
60
|
-
value = argument === undefined
|
|
61
|
-
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
62
|
-
: got;
|
|
63
|
-
else if (argument !== false)
|
|
64
|
-
throw Oops$8.NotFound(this);
|
|
65
|
-
return {
|
|
66
|
-
mount() {
|
|
67
|
-
onUpdate = refresh;
|
|
68
|
-
return () => onUpdate = null;
|
|
69
|
-
},
|
|
70
|
-
render: () => value
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
let compute = argument;
|
|
74
|
-
let suspense;
|
|
75
|
-
let getValue;
|
|
76
|
-
let factory;
|
|
77
|
-
let proxy;
|
|
78
|
-
const found = context.get(this);
|
|
79
|
-
if (!found)
|
|
80
|
-
throw Oops$8.NotFound(this);
|
|
81
|
-
function forceUpdate(action) {
|
|
82
|
-
if (typeof action == "function")
|
|
83
|
-
action = action();
|
|
84
|
-
if (getValue)
|
|
85
|
-
didUpdate(getValue());
|
|
86
|
-
else
|
|
87
|
-
refresh();
|
|
88
|
-
if (action)
|
|
89
|
-
return action.finally(refresh);
|
|
90
|
-
}
|
|
91
|
-
function didUpdate(got) {
|
|
92
|
-
value = got;
|
|
93
|
-
if (suspense) {
|
|
94
|
-
suspense();
|
|
95
|
-
suspense = undefined;
|
|
96
|
-
}
|
|
97
|
-
else
|
|
98
|
-
refresh();
|
|
99
|
-
}
|
|
100
|
-
proxy = Control.watch(found, () => factory ? null : onUpdate);
|
|
101
|
-
getValue = () => compute.call(proxy, proxy, forceUpdate);
|
|
102
|
-
value = getValue();
|
|
103
|
-
if (value === null) {
|
|
104
|
-
getValue = undefined;
|
|
105
|
-
onUpdate = null;
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (typeof value == "function") {
|
|
109
|
-
const get = value;
|
|
110
|
-
Control.watch(proxy, () => onUpdate);
|
|
111
|
-
factory = true;
|
|
112
|
-
compute = () => get();
|
|
113
|
-
value = get();
|
|
114
|
-
}
|
|
115
|
-
if (value instanceof Promise) {
|
|
116
|
-
onUpdate = null;
|
|
117
|
-
value.then(didUpdate);
|
|
118
|
-
value = undefined;
|
|
119
|
-
}
|
|
120
|
-
else
|
|
121
|
-
onUpdate = () => {
|
|
122
|
-
const next = getValue();
|
|
123
|
-
if (value !== next)
|
|
124
|
-
didUpdate(next);
|
|
125
|
-
};
|
|
126
|
-
return {
|
|
127
|
-
mount: () => () => {
|
|
128
|
-
onUpdate = null;
|
|
129
|
-
},
|
|
130
|
-
render: () => {
|
|
131
|
-
if (value !== undefined)
|
|
132
|
-
return value;
|
|
133
|
-
if (onUpdate)
|
|
134
|
-
return null;
|
|
135
|
-
throw new Promise(res => {
|
|
136
|
-
suspense = res;
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function use$1(apply, repeat) {
|
|
144
|
-
const render = Control.use(dispatch => {
|
|
145
|
-
const instance = this.new();
|
|
146
|
-
const local = Control.watch(instance, () => onUpdate);
|
|
147
|
-
const refresh = () => dispatch(x => x + 1);
|
|
148
|
-
let onUpdate;
|
|
149
|
-
let shouldApply = !!apply;
|
|
150
|
-
return {
|
|
151
|
-
instance,
|
|
152
|
-
mount() {
|
|
153
|
-
onUpdate = refresh;
|
|
154
|
-
return () => {
|
|
155
|
-
onUpdate = null;
|
|
156
|
-
instance.null();
|
|
157
|
-
};
|
|
158
|
-
},
|
|
159
|
-
render(props) {
|
|
160
|
-
if (shouldApply) {
|
|
161
|
-
onUpdate = undefined;
|
|
162
|
-
if (typeof props == "function")
|
|
163
|
-
props(instance);
|
|
164
|
-
else if (props)
|
|
165
|
-
for (const key in instance)
|
|
166
|
-
if (props.hasOwnProperty(key))
|
|
167
|
-
instance[key] = props[key];
|
|
168
|
-
if (!repeat)
|
|
169
|
-
shouldApply = false;
|
|
170
|
-
instance.set(0).then(() => onUpdate = refresh);
|
|
171
|
-
}
|
|
172
|
-
return local;
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
});
|
|
176
|
-
return render(apply);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const Oops$7 = issues({
|
|
180
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
181
|
-
Destoryed: () => "Model is destroyed."
|
|
182
|
-
});
|
|
183
|
-
function suspense(source, key) {
|
|
184
|
-
const error = Oops$7.NotReady(source.subject, key);
|
|
185
|
-
const watch = source.observers.get(key);
|
|
186
|
-
const promise = new Promise((resolve, reject) => {
|
|
187
|
-
function onUpdate(key) {
|
|
188
|
-
if (key)
|
|
189
|
-
return () => {
|
|
190
|
-
if (source.state[key] !== undefined) {
|
|
191
|
-
watch.delete(onUpdate);
|
|
192
|
-
resolve();
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
if (key === null)
|
|
196
|
-
reject(Oops$7.Destoryed());
|
|
197
|
-
}
|
|
198
|
-
watch.add(onUpdate);
|
|
199
|
-
});
|
|
200
|
-
return assign(promise, {
|
|
201
|
-
toString: () => String(error),
|
|
202
|
-
name: "Suspense",
|
|
203
|
-
message: error.message,
|
|
204
|
-
stack: error.stack
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
function mayRetry(fn) {
|
|
208
|
-
const retry = (err) => {
|
|
209
|
-
if (err instanceof Promise)
|
|
210
|
-
return err.then(compute);
|
|
211
|
-
else
|
|
212
|
-
throw err;
|
|
213
|
-
};
|
|
214
|
-
const compute = () => {
|
|
215
|
-
try {
|
|
216
|
-
const output = fn();
|
|
217
|
-
return output instanceof Promise
|
|
218
|
-
? output.catch(retry)
|
|
219
|
-
: output;
|
|
220
|
-
}
|
|
221
|
-
catch (err) {
|
|
222
|
-
return retry(err);
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
return compute();
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
const Oops$6 = issues({
|
|
229
|
-
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
230
|
-
});
|
|
231
|
-
function createEffect(source, callback) {
|
|
232
|
-
return control(source, self => {
|
|
233
|
-
let { subject } = self;
|
|
234
|
-
let unSet;
|
|
235
|
-
let busy = false;
|
|
236
|
-
function invoke() {
|
|
237
|
-
if (busy)
|
|
238
|
-
return;
|
|
239
|
-
const output = mayRetry(() => {
|
|
240
|
-
if (typeof unSet == "function")
|
|
241
|
-
unSet();
|
|
242
|
-
unSet = callback.call(subject, subject);
|
|
243
|
-
if (unSet instanceof Promise)
|
|
244
|
-
unSet = undefined;
|
|
245
|
-
if (unSet && typeof unSet !== "function")
|
|
246
|
-
throw Oops$6.BadCallback();
|
|
247
|
-
});
|
|
248
|
-
if (output instanceof Promise) {
|
|
249
|
-
output.finally(() => busy = false);
|
|
250
|
-
busy = true;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
let refresh;
|
|
254
|
-
subject = watch(subject, () => refresh);
|
|
255
|
-
self.followers.add(key => (key === null || refresh === null ? refresh : undefined));
|
|
256
|
-
invoke();
|
|
257
|
-
refresh = invoke;
|
|
258
|
-
return () => refresh = null;
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
function createValueEffect(callback, ignoreNull) {
|
|
262
|
-
let unSet;
|
|
263
|
-
return function (value) {
|
|
264
|
-
if (typeof unSet == "function")
|
|
265
|
-
unSet = void unSet(value);
|
|
266
|
-
if (value === null && ignoreNull)
|
|
267
|
-
return;
|
|
268
|
-
const out = callback.call(this, value);
|
|
269
|
-
if (typeof out == "boolean")
|
|
270
|
-
return out;
|
|
271
|
-
if (!out || out instanceof Promise)
|
|
272
|
-
return;
|
|
273
|
-
if (typeof out == "function")
|
|
274
|
-
unSet = out;
|
|
275
|
-
else
|
|
276
|
-
throw Oops$6.BadCallback();
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
function getMethod(argument, callback, once) {
|
|
281
|
-
if (typeof argument == "function")
|
|
282
|
-
return createEffect(this, argument);
|
|
283
|
-
const self = control(this, true);
|
|
284
|
-
function get(key) {
|
|
285
|
-
const value = self.state[key];
|
|
286
|
-
return value instanceof Model ? value.get() : value;
|
|
287
|
-
}
|
|
288
|
-
const extract = typeof argument == "string"
|
|
289
|
-
? () => get(argument)
|
|
290
|
-
: () => {
|
|
291
|
-
const output = {};
|
|
292
|
-
for (const key of argument || keys(self.state))
|
|
293
|
-
output[key] = get(key);
|
|
294
|
-
return output;
|
|
295
|
-
};
|
|
296
|
-
if (typeof callback != "function")
|
|
297
|
-
return extract();
|
|
298
|
-
const select = typeof argument == "string" ? [argument] : argument;
|
|
299
|
-
const invoke = () => callback(extract(), self.latest || []);
|
|
300
|
-
if (select)
|
|
301
|
-
for (const key of select)
|
|
302
|
-
try {
|
|
303
|
-
const value = self.subject[key];
|
|
304
|
-
if (!(key in self.state))
|
|
305
|
-
self.watch(key, { value });
|
|
306
|
-
}
|
|
307
|
-
catch (e) {
|
|
308
|
-
// TODO: should this be caught?
|
|
309
|
-
}
|
|
310
|
-
if (once === undefined)
|
|
311
|
-
invoke();
|
|
312
|
-
const remove = self.addListener(key => {
|
|
313
|
-
if (!select || select.includes(key)) {
|
|
314
|
-
if (once)
|
|
315
|
-
remove();
|
|
316
|
-
return invoke;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
return remove;
|
|
320
|
-
}
|
|
321
|
-
function setMethod(arg1, arg2) {
|
|
322
|
-
const self = control(this, true);
|
|
323
|
-
const { state } = self;
|
|
324
|
-
let timeout = 0;
|
|
325
|
-
switch (typeof arg1) {
|
|
326
|
-
case "string":
|
|
327
|
-
if (1 in arguments)
|
|
328
|
-
if (arg1 in state)
|
|
329
|
-
state[arg1] = arg2;
|
|
330
|
-
else
|
|
331
|
-
self.watch(arg1, { value: arg2 });
|
|
332
|
-
self.update(arg1);
|
|
333
|
-
break;
|
|
334
|
-
case "object":
|
|
335
|
-
for (const key in state)
|
|
336
|
-
if (key in arg1 && (!arg2 || arg2.includes(key))) {
|
|
337
|
-
state[key] = arg1[key];
|
|
338
|
-
self.update(key);
|
|
339
|
-
}
|
|
340
|
-
break;
|
|
341
|
-
default:
|
|
342
|
-
timeout = arg1;
|
|
343
|
-
}
|
|
344
|
-
return new Promise((resolve) => {
|
|
345
|
-
if (!self.frame.size && timeout === 0)
|
|
346
|
-
resolve(false);
|
|
347
|
-
const remove = self.addListener(() => {
|
|
348
|
-
remove();
|
|
349
|
-
return () => resolve(self.latest);
|
|
350
|
-
});
|
|
351
|
-
if (timeout > 0)
|
|
352
|
-
setTimeout(() => {
|
|
353
|
-
remove();
|
|
354
|
-
resolve(false);
|
|
355
|
-
}, timeout);
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
class Model {
|
|
360
|
-
constructor(id) {
|
|
361
|
-
new Control(this, id === undefined ? uid() : id);
|
|
362
|
-
}
|
|
363
|
-
/** Mark this instance for garbage collection. */
|
|
364
|
-
null() {
|
|
365
|
-
control(this, true).clear();
|
|
366
|
-
}
|
|
367
|
-
/**
|
|
368
|
-
* Creates a new instance of this controller.
|
|
369
|
-
*
|
|
370
|
-
* Beyond `new this(...)`, method will activate managed-state.
|
|
371
|
-
*
|
|
372
|
-
* @param args - arguments sent to constructor
|
|
373
|
-
*/
|
|
374
|
-
static new(...args) {
|
|
375
|
-
const instance = new this(...args);
|
|
376
|
-
control(instance, true);
|
|
377
|
-
return instance;
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Static equivalent of `x instanceof this`.
|
|
381
|
-
*
|
|
382
|
-
* Will determine if provided class is a subtype of this one.
|
|
383
|
-
*/
|
|
384
|
-
static is(maybe) {
|
|
385
|
-
return (typeof maybe == "function" &&
|
|
386
|
-
maybe.prototype instanceof this);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
Model.get = get$1;
|
|
390
|
-
Model.use = use$1;
|
|
391
|
-
defineProperty(Model, "toString", {
|
|
392
|
-
value() {
|
|
393
|
-
return this.name;
|
|
394
|
-
}
|
|
395
|
-
});
|
|
396
|
-
defineProperties(Model.prototype, {
|
|
397
|
-
get: { value: getMethod },
|
|
398
|
-
set: { value: setMethod },
|
|
399
|
-
toString: {
|
|
400
|
-
configurable: true,
|
|
401
|
-
value() {
|
|
402
|
-
return `${this.constructor.name}-${control(this).id}`;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
/* TODO: Remove below on 1.0.0 release. */
|
|
407
|
-
defineProperty(Model, "isTypeof", {
|
|
408
|
-
get() {
|
|
409
|
-
throw new Error("Model.isTypeof method was renamed. Use Model.is instead.");
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
defineProperties(Model.prototype, {
|
|
413
|
-
is: {
|
|
414
|
-
configurable: true,
|
|
415
|
-
get() {
|
|
416
|
-
throw new Error("Model.is property is now is only available from a hook.");
|
|
417
|
-
}
|
|
418
|
-
},
|
|
419
|
-
on: {
|
|
420
|
-
configurable: true,
|
|
421
|
-
writable: true,
|
|
422
|
-
value() {
|
|
423
|
-
throw new Error("Model.on() is deprecated. Use Model.get or Model.set instead.");
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
/** Random alphanumberic of length 6. Will always start with a letter. */
|
|
428
|
-
function uid() {
|
|
429
|
-
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
430
|
-
}
|
|
30
|
+
const { assign, create, defineProperty, entries, freeze, isFrozen, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
431
31
|
|
|
432
|
-
const Oops$5 = issues({
|
|
433
|
-
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
434
|
-
});
|
|
435
32
|
const REGISTER = new WeakMap();
|
|
436
33
|
const OBSERVER = new WeakMap();
|
|
437
34
|
const INSTRUCT = new Map();
|
|
438
35
|
const PENDING$1 = new WeakMap();
|
|
439
36
|
const PARENTS = new WeakMap();
|
|
37
|
+
const LIFECYCLE = {
|
|
38
|
+
ready: new Set(),
|
|
39
|
+
dispatch: new Set(),
|
|
40
|
+
update: new Set(),
|
|
41
|
+
didUpdate: new Set(),
|
|
42
|
+
};
|
|
440
43
|
class Control {
|
|
44
|
+
static on(event, callback) {
|
|
45
|
+
LIFECYCLE[event].add(callback);
|
|
46
|
+
return () => LIFECYCLE[event].delete(callback);
|
|
47
|
+
}
|
|
441
48
|
constructor(subject, id) {
|
|
442
49
|
this.state = {};
|
|
443
|
-
this.frame =
|
|
444
|
-
this.
|
|
445
|
-
this.
|
|
446
|
-
this.id = id;
|
|
50
|
+
this.frame = freeze({});
|
|
51
|
+
this.listeners = new Map();
|
|
52
|
+
this.id = `${subject.constructor}-${id ? String(id) : uid()}`;
|
|
447
53
|
this.subject = subject;
|
|
448
54
|
REGISTER.set(subject, this);
|
|
449
55
|
if (id !== false)
|
|
450
|
-
PENDING$1.set(this, new Set(
|
|
451
|
-
}
|
|
452
|
-
add(key) {
|
|
453
|
-
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
454
|
-
const instruction = INSTRUCT.get(value);
|
|
455
|
-
if (typeof instruction == "function") {
|
|
456
|
-
INSTRUCT.delete(value);
|
|
457
|
-
instruction(this, key);
|
|
458
|
-
}
|
|
459
|
-
else if (value instanceof Model)
|
|
460
|
-
setRecursive(this, key, value);
|
|
461
|
-
else
|
|
462
|
-
this.watch(key, { value });
|
|
56
|
+
PENDING$1.set(this, new Set(LIFECYCLE.ready));
|
|
463
57
|
}
|
|
464
58
|
watch(key, output) {
|
|
465
|
-
const { state } = this;
|
|
59
|
+
const { state, subject, listeners } = this;
|
|
466
60
|
const { set, enumerable = true } = output;
|
|
467
|
-
const subs = new Set();
|
|
468
|
-
this.observers.set(key, subs);
|
|
469
61
|
if ("value" in output)
|
|
470
62
|
state[key] = output.value;
|
|
471
|
-
defineProperty(
|
|
63
|
+
defineProperty(subject, key, {
|
|
472
64
|
enumerable,
|
|
473
65
|
set: set === false
|
|
474
66
|
? undefined
|
|
475
|
-
:
|
|
67
|
+
: (next) => {
|
|
68
|
+
const previous = state[key];
|
|
69
|
+
if (next !== previous) {
|
|
70
|
+
state[key] = next;
|
|
71
|
+
if (set && set.call(subject, next, previous) === false)
|
|
72
|
+
state[key] = previous;
|
|
73
|
+
else
|
|
74
|
+
this.update(key);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
476
77
|
get() {
|
|
477
|
-
const event = OBSERVER.get(this);
|
|
478
|
-
if (event)
|
|
479
|
-
subs.add(event);
|
|
480
78
|
const value = output.get
|
|
481
|
-
? output.get(this)
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
79
|
+
? output.get(this)
|
|
80
|
+
: state[key];
|
|
81
|
+
const observer = OBSERVER.get(this);
|
|
82
|
+
if (observer) {
|
|
83
|
+
const keys = listeners.get(observer);
|
|
84
|
+
listeners.set(observer, new Set(keys).add(key));
|
|
85
|
+
return watch(value, observer);
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
485
88
|
}
|
|
486
89
|
});
|
|
487
90
|
}
|
|
488
|
-
|
|
489
|
-
const { state, subject } = this;
|
|
490
|
-
|
|
491
|
-
if (value !== state[key])
|
|
492
|
-
switch (callback && callback.call(subject, value)) {
|
|
493
|
-
case undefined:
|
|
494
|
-
state[key] = value;
|
|
495
|
-
case true:
|
|
496
|
-
this.update(key);
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
update(key) {
|
|
501
|
-
const { frame } = this;
|
|
502
|
-
if (frame.has(key))
|
|
91
|
+
update(key, value) {
|
|
92
|
+
const { state, subject, listeners } = this;
|
|
93
|
+
if (!listeners || 1 in arguments && value === state[key])
|
|
503
94
|
return;
|
|
504
|
-
if (
|
|
505
|
-
this.
|
|
506
|
-
|
|
507
|
-
this.
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
95
|
+
if (isFrozen(this.frame)) {
|
|
96
|
+
this.frame = {};
|
|
97
|
+
enqueue(() => {
|
|
98
|
+
freeze(this.frame);
|
|
99
|
+
listeners.forEach((subs, cb) => {
|
|
100
|
+
if (!subs) {
|
|
101
|
+
const notify = cb(undefined, subject);
|
|
102
|
+
if (notify)
|
|
103
|
+
enqueue(notify);
|
|
104
|
+
}
|
|
512
105
|
});
|
|
513
|
-
frame.clear();
|
|
514
106
|
});
|
|
515
107
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
108
|
+
if (1 in arguments)
|
|
109
|
+
state[key] = value;
|
|
110
|
+
if (key in this.frame)
|
|
111
|
+
return;
|
|
112
|
+
this.frame[key] = state[key];
|
|
113
|
+
for (const [cb, keys] of listeners)
|
|
114
|
+
if (!keys || keys.has(key)) {
|
|
115
|
+
const notify = cb(key, subject);
|
|
521
116
|
if (notify === null)
|
|
522
|
-
|
|
117
|
+
listeners.delete(cb);
|
|
523
118
|
else if (notify)
|
|
524
|
-
|
|
119
|
+
enqueue(notify);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
fetch(key, required) {
|
|
123
|
+
const { state, subject } = this;
|
|
124
|
+
return () => {
|
|
125
|
+
if (key in state || required === false) {
|
|
126
|
+
const value = state[key];
|
|
127
|
+
if (value !== undefined || !required)
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
const error = new Error(`${subject}.${key} is not yet available.`);
|
|
131
|
+
const promise = new Promise((resolve, reject) => {
|
|
132
|
+
function check() {
|
|
133
|
+
if (state[key] !== undefined) {
|
|
134
|
+
remove();
|
|
135
|
+
resolve();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const remove = this.addListener((k) => {
|
|
139
|
+
if (k === key)
|
|
140
|
+
return check;
|
|
141
|
+
if (k === null)
|
|
142
|
+
reject(new Error(`${subject} is destroyed.`));
|
|
143
|
+
});
|
|
525
144
|
});
|
|
526
|
-
|
|
145
|
+
throw assign(promise, {
|
|
146
|
+
toString: () => String(error),
|
|
147
|
+
name: "Suspense",
|
|
148
|
+
message: error.message,
|
|
149
|
+
stack: error.stack
|
|
150
|
+
});
|
|
151
|
+
};
|
|
527
152
|
}
|
|
528
153
|
addListener(fn) {
|
|
529
|
-
this.
|
|
530
|
-
return () => this.
|
|
154
|
+
this.listeners.set(fn, undefined);
|
|
155
|
+
return () => this.listeners.delete(fn);
|
|
531
156
|
}
|
|
532
157
|
clear() {
|
|
533
|
-
this.
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
cb && cb();
|
|
537
|
-
});
|
|
538
|
-
});
|
|
539
|
-
this.observers.clear();
|
|
158
|
+
this.listeners.forEach((_, fn) => fn(null, this));
|
|
159
|
+
this.listeners.clear();
|
|
160
|
+
freeze(this.state);
|
|
540
161
|
}
|
|
541
162
|
}
|
|
542
|
-
Control.ready = new Set();
|
|
543
|
-
Control.after = new Set();
|
|
544
|
-
Control.before = new Set();
|
|
545
|
-
Control.pending = new Set();
|
|
546
|
-
Control.for = control;
|
|
547
|
-
Control.apply = apply;
|
|
548
163
|
Control.watch = watch;
|
|
164
|
+
Control.for = control;
|
|
165
|
+
Control.add = add;
|
|
549
166
|
function control(subject, ready) {
|
|
550
|
-
const
|
|
551
|
-
const pending = PENDING$1.get(
|
|
167
|
+
const self = REGISTER.get(subject.is);
|
|
168
|
+
const pending = PENDING$1.get(self);
|
|
552
169
|
if (typeof ready == "function") {
|
|
553
|
-
if (
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
170
|
+
if (pending) {
|
|
171
|
+
let done;
|
|
172
|
+
pending.add(() => done = ready(self));
|
|
173
|
+
return () => done && done();
|
|
174
|
+
}
|
|
175
|
+
return ready(self);
|
|
558
176
|
}
|
|
559
177
|
if (pending && ready) {
|
|
560
|
-
for (const key in
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
178
|
+
for (const key in subject) {
|
|
179
|
+
const { value } = getOwnPropertyDescriptor(subject, key);
|
|
180
|
+
const instruction = INSTRUCT.get(value);
|
|
181
|
+
let desc = { value };
|
|
182
|
+
if (instruction) {
|
|
183
|
+
INSTRUCT.delete(value);
|
|
184
|
+
delete subject[key];
|
|
185
|
+
const out = instruction.call(self, key, self);
|
|
186
|
+
desc = typeof out == "function" ? { get: out } : out;
|
|
187
|
+
}
|
|
188
|
+
if (desc)
|
|
189
|
+
self.watch(key, desc);
|
|
190
|
+
}
|
|
191
|
+
PENDING$1.delete(self);
|
|
192
|
+
pending.forEach(cb => cb(self));
|
|
564
193
|
}
|
|
565
|
-
return
|
|
194
|
+
return self;
|
|
566
195
|
}
|
|
567
|
-
function
|
|
568
|
-
const {
|
|
569
|
-
if (!
|
|
196
|
+
function enqueue(event) {
|
|
197
|
+
const { update, didUpdate, dispatch } = LIFECYCLE;
|
|
198
|
+
if (!dispatch.size)
|
|
570
199
|
setTimeout(() => {
|
|
571
|
-
|
|
572
|
-
|
|
200
|
+
update.forEach(x => x());
|
|
201
|
+
dispatch.forEach(event => {
|
|
573
202
|
try {
|
|
574
|
-
|
|
203
|
+
event();
|
|
575
204
|
}
|
|
576
205
|
catch (err) {
|
|
577
206
|
console.error(err);
|
|
578
207
|
}
|
|
579
208
|
});
|
|
580
|
-
|
|
581
|
-
|
|
209
|
+
dispatch.clear();
|
|
210
|
+
didUpdate.forEach(x => x());
|
|
582
211
|
}, 0);
|
|
583
|
-
|
|
584
|
-
}
|
|
585
|
-
function setRecursive(on, key, value) {
|
|
586
|
-
const set = (next) => {
|
|
587
|
-
if (next instanceof value.constructor) {
|
|
588
|
-
on.state[key] = next;
|
|
589
|
-
parent(next, on.subject);
|
|
590
|
-
control(next, true);
|
|
591
|
-
return true;
|
|
592
|
-
}
|
|
593
|
-
throw Oops$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
594
|
-
};
|
|
595
|
-
on.watch(key, { set });
|
|
596
|
-
set(value);
|
|
212
|
+
dispatch.add(event);
|
|
597
213
|
}
|
|
598
|
-
function parent(
|
|
214
|
+
function parent(from, assign) {
|
|
599
215
|
if (!assign)
|
|
600
|
-
return PARENTS.get(
|
|
601
|
-
PARENTS.set(
|
|
216
|
+
return PARENTS.get(from);
|
|
217
|
+
PARENTS.set(from, assign);
|
|
602
218
|
}
|
|
603
|
-
function watch(value,
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
219
|
+
function watch(value, argument) {
|
|
220
|
+
const control = REGISTER.get(value);
|
|
221
|
+
if (control) {
|
|
222
|
+
if (!OBSERVER.has(value))
|
|
223
|
+
REGISTER.set(value = create(value), control);
|
|
224
|
+
OBSERVER.set(value, argument);
|
|
608
225
|
}
|
|
609
|
-
OBSERVER.set(value, cb);
|
|
610
226
|
return value;
|
|
611
227
|
}
|
|
612
|
-
function
|
|
228
|
+
function add(instruction) {
|
|
613
229
|
const placeholder = Symbol("instruction");
|
|
614
|
-
INSTRUCT.set(placeholder,
|
|
615
|
-
delete onto.subject[key];
|
|
616
|
-
const output = instruction.call(onto, key, onto);
|
|
617
|
-
if (output)
|
|
618
|
-
onto.watch(key, typeof output == "function" ? { get: output } : output);
|
|
619
|
-
});
|
|
230
|
+
INSTRUCT.set(placeholder, instruction);
|
|
620
231
|
return placeholder;
|
|
232
|
+
}
|
|
233
|
+
/** Random alphanumberic of length 6. Will always start with a letter. */
|
|
234
|
+
function uid() {
|
|
235
|
+
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
621
236
|
}
|
|
622
237
|
|
|
623
|
-
|
|
624
|
-
|
|
238
|
+
class Model {
|
|
239
|
+
constructor(id) {
|
|
240
|
+
defineProperty(this, "is", { value: this });
|
|
241
|
+
new Control(this, id);
|
|
242
|
+
}
|
|
243
|
+
get(arg1) {
|
|
244
|
+
return typeof arg1 == "function"
|
|
245
|
+
? effect(this, arg1)
|
|
246
|
+
: extract(this);
|
|
247
|
+
}
|
|
248
|
+
set(arg1, arg2) {
|
|
249
|
+
return typeof arg1 == "function"
|
|
250
|
+
? control(this, c => c.addListener(k => k && arg1(k)))
|
|
251
|
+
: nextUpdate(this, arg1, arg2);
|
|
252
|
+
}
|
|
253
|
+
/** Mark this instance for garbage collection. */
|
|
254
|
+
null() {
|
|
255
|
+
control(this).clear();
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Creates a new instance of this controller.
|
|
259
|
+
*
|
|
260
|
+
* Beyond `new this(...)`, method will activate managed-state.
|
|
261
|
+
*
|
|
262
|
+
* @param args - arguments sent to constructor
|
|
263
|
+
*/
|
|
264
|
+
static new(...args) {
|
|
265
|
+
const instance = new this(...args);
|
|
266
|
+
control(instance, true);
|
|
267
|
+
return instance;
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Static equivalent of `x instanceof this`.
|
|
271
|
+
* Determines if provided class is a subtype of this one.
|
|
272
|
+
* If so, language server will make available all static
|
|
273
|
+
* methods and properties of this class.
|
|
274
|
+
*/
|
|
275
|
+
static is(maybe) {
|
|
276
|
+
return typeof maybe == "function" && maybe.prototype instanceof this;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
defineProperty(Model.prototype, "toString", {
|
|
280
|
+
value() {
|
|
281
|
+
return control(this).id;
|
|
282
|
+
}
|
|
625
283
|
});
|
|
284
|
+
defineProperty(Model, "toString", {
|
|
285
|
+
value() {
|
|
286
|
+
return this.name;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
function extract(target) {
|
|
291
|
+
const cache = new Map();
|
|
292
|
+
function get(value) {
|
|
293
|
+
if (value instanceof Model) {
|
|
294
|
+
let flat = cache.get(value);
|
|
295
|
+
if (!flat) {
|
|
296
|
+
cache.set(value, flat = {});
|
|
297
|
+
const { state } = control(value);
|
|
298
|
+
entries(state).forEach(([key, value]) => {
|
|
299
|
+
flat[key] = get(value);
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return flat;
|
|
303
|
+
}
|
|
304
|
+
return value;
|
|
305
|
+
}
|
|
306
|
+
return get(target);
|
|
307
|
+
}
|
|
308
|
+
function nextUpdate(target, arg1, arg2) {
|
|
309
|
+
return new Promise((resolve, reject) => {
|
|
310
|
+
control(target, self => {
|
|
311
|
+
if (isFrozen(self.frame) && typeof arg1 != "number") {
|
|
312
|
+
resolve(false);
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const callback = () => resolve(self.frame);
|
|
316
|
+
const remove = self.addListener((key) => {
|
|
317
|
+
if (!arg2 || key && arg2(key) === true) {
|
|
318
|
+
remove();
|
|
319
|
+
if (timeout)
|
|
320
|
+
clearTimeout(timeout);
|
|
321
|
+
return callback;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
const timeout = typeof arg1 == "number" && setTimeout(() => {
|
|
325
|
+
remove();
|
|
326
|
+
reject(arg1);
|
|
327
|
+
}, arg1);
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
function effect(target, callback) {
|
|
332
|
+
return control(target, self => {
|
|
333
|
+
let refresh;
|
|
334
|
+
let unSet;
|
|
335
|
+
function invoke() {
|
|
336
|
+
if (unSet)
|
|
337
|
+
unSet();
|
|
338
|
+
try {
|
|
339
|
+
const out = callback.call(target, target);
|
|
340
|
+
unSet = typeof out == "function" ? out : undefined;
|
|
341
|
+
}
|
|
342
|
+
catch (err) {
|
|
343
|
+
if (err instanceof Promise) {
|
|
344
|
+
err.then(() => (refresh = invoke)());
|
|
345
|
+
refresh = undefined;
|
|
346
|
+
}
|
|
347
|
+
else
|
|
348
|
+
console.error(err);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
target = watch(target, () => refresh);
|
|
352
|
+
self.addListener(key => {
|
|
353
|
+
if (!refresh)
|
|
354
|
+
return refresh;
|
|
355
|
+
if (key === null && unSet)
|
|
356
|
+
unSet();
|
|
357
|
+
});
|
|
358
|
+
invoke();
|
|
359
|
+
refresh = invoke;
|
|
360
|
+
return () => {
|
|
361
|
+
refresh = null;
|
|
362
|
+
};
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
function attempt(fn) {
|
|
366
|
+
function retry(err) {
|
|
367
|
+
if (err instanceof Promise)
|
|
368
|
+
return err.then(compute);
|
|
369
|
+
else
|
|
370
|
+
throw err;
|
|
371
|
+
}
|
|
372
|
+
function compute() {
|
|
373
|
+
try {
|
|
374
|
+
const output = fn();
|
|
375
|
+
return output instanceof Promise
|
|
376
|
+
? output.catch(retry)
|
|
377
|
+
: output;
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
return retry(err);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return compute();
|
|
384
|
+
}
|
|
385
|
+
|
|
626
386
|
function run(task) {
|
|
627
|
-
return
|
|
387
|
+
return add((key, control) => {
|
|
628
388
|
let pending = false;
|
|
629
389
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
630
390
|
if (pending)
|
|
631
|
-
return Promise.reject(
|
|
391
|
+
return Promise.reject(new Error(`Invoked action ${key} but one is already active.`));
|
|
632
392
|
pending = true;
|
|
633
393
|
control.update(key);
|
|
634
394
|
try {
|
|
635
|
-
return yield
|
|
395
|
+
return yield attempt(() => task.apply(control.subject, args));
|
|
636
396
|
}
|
|
637
397
|
finally {
|
|
638
398
|
pending = false;
|
|
639
399
|
control.update(key);
|
|
640
400
|
}
|
|
641
401
|
});
|
|
642
|
-
control.state[key] = undefined;
|
|
643
402
|
defineProperty(invoke, "active", {
|
|
644
403
|
get: () => pending
|
|
645
404
|
});
|
|
@@ -650,107 +409,93 @@ function run(task) {
|
|
|
650
409
|
});
|
|
651
410
|
}
|
|
652
411
|
|
|
653
|
-
const Oops$3 = issues({
|
|
654
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
655
|
-
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
656
|
-
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
657
|
-
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
658
|
-
AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
|
|
659
|
-
});
|
|
660
412
|
function get(arg0, arg1) {
|
|
661
|
-
return
|
|
413
|
+
return add((key, control) => {
|
|
662
414
|
let { subject } = control;
|
|
663
415
|
if (typeof arg0 == "symbol")
|
|
664
|
-
throw
|
|
665
|
-
let source =
|
|
416
|
+
throw new Error(`Attempted to use an instruction result (probably use or get) as computed source for ${subject}.${key}. This is not allowed.`);
|
|
417
|
+
let source = resolve => resolve(subject);
|
|
666
418
|
if (arg0 instanceof Model)
|
|
667
419
|
subject = arg0;
|
|
668
420
|
else if (Model.is(arg0)) {
|
|
669
421
|
const hasParent = parent(subject);
|
|
670
422
|
if (!hasParent) {
|
|
671
423
|
if (arg1 === true)
|
|
672
|
-
throw
|
|
673
|
-
|
|
674
|
-
|
|
424
|
+
throw new Error(`New ${subject} created standalone but requires parent of type ${arg0}.`);
|
|
425
|
+
if (!get.from)
|
|
426
|
+
throw new Error(`Using context requires an adapter. If you are only testing, define \`get.context\` to simulate one.`);
|
|
427
|
+
const fetch = get.from(subject);
|
|
428
|
+
source = (resolve) => {
|
|
675
429
|
fetch(context => {
|
|
676
430
|
const model = context.get(arg0);
|
|
677
431
|
if (model)
|
|
678
|
-
|
|
432
|
+
resolve(model);
|
|
679
433
|
else if (arg1 !== false)
|
|
680
|
-
throw
|
|
434
|
+
throw new Error(`Attempted to find an instance of ${arg0} in context. It is required by ${subject}, but one could not be found.`);
|
|
681
435
|
});
|
|
682
436
|
};
|
|
683
437
|
}
|
|
684
438
|
else if (!arg0 || hasParent instanceof arg0)
|
|
685
439
|
subject = hasParent;
|
|
686
440
|
else
|
|
687
|
-
throw
|
|
441
|
+
throw new Error(`New ${subject} created as child of ${hasParent}, but must be instanceof ${arg0}.`);
|
|
688
442
|
}
|
|
689
443
|
else if (typeof arg0 == "function")
|
|
690
444
|
arg1 = arg0.call(subject, key, subject);
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
445
|
+
if (typeof arg1 == "function")
|
|
446
|
+
return compute(control, key, source, arg1);
|
|
447
|
+
source(got => control.update(key, got));
|
|
448
|
+
return control.fetch(key, arg1 !== false);
|
|
694
449
|
});
|
|
695
450
|
}
|
|
696
|
-
function recursive(parent, key, source, required) {
|
|
697
|
-
let waiting;
|
|
698
|
-
if (source)
|
|
699
|
-
source((got) => {
|
|
700
|
-
parent.state[key] = got;
|
|
701
|
-
if (waiting)
|
|
702
|
-
parent.update(key);
|
|
703
|
-
});
|
|
704
|
-
waiting = true;
|
|
705
|
-
return () => {
|
|
706
|
-
const value = parent.state[key];
|
|
707
|
-
if (value)
|
|
708
|
-
return value;
|
|
709
|
-
if (required !== false)
|
|
710
|
-
throw suspense(parent, key);
|
|
711
|
-
};
|
|
712
|
-
}
|
|
713
451
|
const ORDER = new WeakMap();
|
|
714
452
|
const PENDING = new Set();
|
|
715
453
|
let OFFSET = 0;
|
|
716
|
-
function
|
|
717
|
-
const { state } = parent;
|
|
454
|
+
function compute(parent, key, source, setter) {
|
|
455
|
+
const { state, subject } = parent;
|
|
718
456
|
let proxy;
|
|
719
|
-
let active;
|
|
720
457
|
let isAsync;
|
|
721
458
|
let reset;
|
|
722
459
|
function compute(initial) {
|
|
723
|
-
if (parent.frame
|
|
460
|
+
if (key in parent.frame)
|
|
724
461
|
return;
|
|
725
462
|
let next;
|
|
726
463
|
try {
|
|
727
464
|
next = setter.call(proxy, proxy);
|
|
728
465
|
}
|
|
729
466
|
catch (err) {
|
|
730
|
-
|
|
467
|
+
// TODO: address possibility of loop
|
|
468
|
+
if (err instanceof Promise)
|
|
469
|
+
throw err.finally(compute);
|
|
470
|
+
console.warn(`An exception was thrown while ${initial ? "initializing" : "refreshing"} ${subject}.${key}.`);
|
|
731
471
|
if (initial)
|
|
732
472
|
throw err;
|
|
733
473
|
console.error(err);
|
|
734
474
|
}
|
|
735
475
|
if (next !== state[key]) {
|
|
736
|
-
|
|
737
|
-
if (!initial || isAsync)
|
|
476
|
+
if (key in state || isAsync)
|
|
738
477
|
parent.update(key);
|
|
478
|
+
state[key] = next;
|
|
739
479
|
}
|
|
740
480
|
}
|
|
741
481
|
function connect(model) {
|
|
482
|
+
let done;
|
|
742
483
|
if (reset)
|
|
743
484
|
reset();
|
|
744
|
-
let done;
|
|
745
485
|
reset = () => done = true;
|
|
746
|
-
proxy = watch(model, (_,
|
|
486
|
+
proxy = watch(model, (_, updated) => {
|
|
747
487
|
if (done)
|
|
748
488
|
return null;
|
|
749
|
-
if (
|
|
750
|
-
compute();
|
|
751
|
-
else
|
|
489
|
+
if (updated == subject)
|
|
752
490
|
PENDING.add(compute);
|
|
491
|
+
else
|
|
492
|
+
compute();
|
|
753
493
|
});
|
|
494
|
+
output.get = () => {
|
|
495
|
+
if (PENDING.delete(compute))
|
|
496
|
+
compute();
|
|
497
|
+
return state[key];
|
|
498
|
+
};
|
|
754
499
|
try {
|
|
755
500
|
compute(true);
|
|
756
501
|
}
|
|
@@ -758,20 +503,17 @@ function computed(parent, key, source, setter) {
|
|
|
758
503
|
ORDER.set(compute, OFFSET++);
|
|
759
504
|
}
|
|
760
505
|
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
506
|
+
const output = {
|
|
507
|
+
get() {
|
|
508
|
+
output.get = parent.fetch(key);
|
|
764
509
|
source(connect);
|
|
765
510
|
isAsync = true;
|
|
511
|
+
return output.get();
|
|
766
512
|
}
|
|
767
|
-
if (!proxy)
|
|
768
|
-
throw suspense(parent, key);
|
|
769
|
-
if (PENDING.delete(compute))
|
|
770
|
-
compute();
|
|
771
|
-
return state[key];
|
|
772
513
|
};
|
|
514
|
+
return output;
|
|
773
515
|
}
|
|
774
|
-
|
|
516
|
+
Control.on("update", () => {
|
|
775
517
|
while (PENDING.size) {
|
|
776
518
|
let compute;
|
|
777
519
|
for (const item of PENDING)
|
|
@@ -780,21 +522,14 @@ function flushComputed() {
|
|
|
780
522
|
PENDING.delete(compute);
|
|
781
523
|
compute();
|
|
782
524
|
}
|
|
783
|
-
}
|
|
784
|
-
Control.before.add(flushComputed);
|
|
525
|
+
});
|
|
785
526
|
|
|
786
|
-
const Oops$2 = issues({
|
|
787
|
-
BadRefObject: () => `ref instruction does not support object which is not 'this'`
|
|
788
|
-
});
|
|
789
527
|
function ref(arg, arg2) {
|
|
790
|
-
return
|
|
528
|
+
return add((key, source) => {
|
|
529
|
+
const { subject, state } = source;
|
|
791
530
|
let value = {};
|
|
792
|
-
if (
|
|
793
|
-
|
|
794
|
-
else if (arg !== source.subject)
|
|
795
|
-
throw Oops$2.BadRefObject();
|
|
796
|
-
else
|
|
797
|
-
for (const key in source.state)
|
|
531
|
+
if (arg === subject)
|
|
532
|
+
for (const key in state)
|
|
798
533
|
defineProperty(value, key, typeof arg2 == "function" ? {
|
|
799
534
|
configurable: true,
|
|
800
535
|
get() {
|
|
@@ -805,13 +540,32 @@ function ref(arg, arg2) {
|
|
|
805
540
|
} : {
|
|
806
541
|
value: createRef(source, key)
|
|
807
542
|
});
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
543
|
+
else if (typeof arg == "object")
|
|
544
|
+
throw new Error("ref instruction does not support object which is not 'this'");
|
|
545
|
+
else {
|
|
546
|
+
let unSet;
|
|
547
|
+
const set = (value) => {
|
|
548
|
+
source.update(key, value);
|
|
549
|
+
if (!arg)
|
|
550
|
+
return;
|
|
551
|
+
if (unSet)
|
|
552
|
+
unSet = void unSet(value);
|
|
553
|
+
if (value !== null || arg2 === false) {
|
|
554
|
+
const out = arg.call(subject, value);
|
|
555
|
+
if (typeof out == "function")
|
|
556
|
+
unSet = out;
|
|
557
|
+
}
|
|
558
|
+
};
|
|
559
|
+
value = defineProperty(set, "current", {
|
|
560
|
+
get: () => state[key],
|
|
561
|
+
set
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
defineProperty(subject, key, { value });
|
|
811
565
|
});
|
|
812
566
|
}
|
|
813
|
-
function createRef(src, key
|
|
814
|
-
const refObjectFunction = src.
|
|
567
|
+
function createRef(src, key) {
|
|
568
|
+
const refObjectFunction = src.update.bind(src, key);
|
|
815
569
|
defineProperty(refObjectFunction, "current", {
|
|
816
570
|
set: refObjectFunction,
|
|
817
571
|
get: () => src.state[key]
|
|
@@ -819,115 +573,101 @@ function createRef(src, key, cb) {
|
|
|
819
573
|
return refObjectFunction;
|
|
820
574
|
}
|
|
821
575
|
|
|
822
|
-
const Oops$1 = issues({
|
|
823
|
-
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
824
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
825
|
-
});
|
|
826
576
|
function set(value, argument) {
|
|
827
|
-
return
|
|
577
|
+
return add((key, control) => {
|
|
828
578
|
const { state, subject } = control;
|
|
579
|
+
const output = {};
|
|
829
580
|
if (typeof value == "function" || value instanceof Promise) {
|
|
830
|
-
|
|
831
|
-
const init = () => {
|
|
581
|
+
function init() {
|
|
832
582
|
try {
|
|
833
583
|
if (typeof value == "function")
|
|
834
|
-
value =
|
|
584
|
+
value = attempt(value.bind(subject, key, subject));
|
|
835
585
|
if (value instanceof Promise) {
|
|
836
586
|
const pending = value
|
|
837
587
|
.then(value => {
|
|
838
588
|
output.get = undefined;
|
|
839
|
-
|
|
589
|
+
control.update(key, value);
|
|
840
590
|
return value;
|
|
841
591
|
})
|
|
842
592
|
.catch(err => {
|
|
843
593
|
output.get = () => { throw err; };
|
|
844
|
-
})
|
|
845
|
-
.finally(() => {
|
|
846
594
|
control.update(key);
|
|
847
595
|
});
|
|
596
|
+
assign(pending, {
|
|
597
|
+
message: `${subject}.${key} is not yet available.`,
|
|
598
|
+
stack: new Error().stack
|
|
599
|
+
});
|
|
848
600
|
if (argument !== false)
|
|
849
|
-
return () => {
|
|
850
|
-
|
|
851
|
-
throw assign(pending, { message, stack });
|
|
601
|
+
return output.get = () => {
|
|
602
|
+
throw pending;
|
|
852
603
|
};
|
|
853
604
|
}
|
|
854
605
|
else
|
|
855
|
-
|
|
606
|
+
control.update(key, value);
|
|
856
607
|
}
|
|
857
608
|
catch (err) {
|
|
858
|
-
|
|
609
|
+
console.warn(`Generating initial value for ${subject}.${key} failed.`);
|
|
859
610
|
throw err;
|
|
860
611
|
}
|
|
861
|
-
}
|
|
612
|
+
}
|
|
862
613
|
if (argument)
|
|
863
614
|
init();
|
|
864
615
|
else
|
|
865
616
|
output.get = () => {
|
|
866
|
-
const get =
|
|
867
|
-
key in state ? undefined : init();
|
|
617
|
+
const get = key in state ? null : init();
|
|
868
618
|
return get ? get() : state[key];
|
|
869
619
|
};
|
|
870
|
-
return output;
|
|
871
|
-
}
|
|
872
|
-
const set = typeof argument == "function"
|
|
873
|
-
? createValueEffect(argument)
|
|
874
|
-
: undefined;
|
|
875
|
-
if (value !== undefined) {
|
|
876
|
-
state[key] = value;
|
|
877
|
-
return { set };
|
|
878
620
|
}
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
621
|
+
else {
|
|
622
|
+
if (value !== undefined)
|
|
623
|
+
output.value = value;
|
|
624
|
+
else
|
|
625
|
+
output.get = control.fetch(key);
|
|
626
|
+
if (typeof argument == "function") {
|
|
627
|
+
let unSet;
|
|
628
|
+
output.set = function (value, previous) {
|
|
629
|
+
const out = argument.call(this, value, previous);
|
|
630
|
+
if (out === false)
|
|
631
|
+
return out;
|
|
632
|
+
if (typeof unSet == "function")
|
|
633
|
+
unSet = void unSet(value);
|
|
634
|
+
if (typeof out == "function")
|
|
635
|
+
unSet = out;
|
|
636
|
+
};
|
|
884
637
|
}
|
|
885
|
-
}
|
|
886
|
-
if (set)
|
|
887
|
-
output.set = function (value) {
|
|
888
|
-
output.set = set;
|
|
889
|
-
state[key] = state[key];
|
|
890
|
-
return set.call(this, value);
|
|
891
|
-
};
|
|
638
|
+
}
|
|
892
639
|
return output;
|
|
893
640
|
});
|
|
894
641
|
}
|
|
895
642
|
|
|
896
643
|
function use(input, argument) {
|
|
897
|
-
return
|
|
898
|
-
const {
|
|
644
|
+
return add((key, source) => {
|
|
645
|
+
const { subject, state } = source;
|
|
899
646
|
if (typeof input === "function")
|
|
900
647
|
input = new input();
|
|
901
648
|
function set(next) {
|
|
649
|
+
if (input instanceof Model && !(next instanceof input.constructor))
|
|
650
|
+
throw new Error(`${subject}.${key} expected Model of type ${input.constructor} but got ${next}.`);
|
|
902
651
|
if (next instanceof Model) {
|
|
903
652
|
parent(next, subject);
|
|
904
653
|
control(next, true);
|
|
905
654
|
}
|
|
906
|
-
else if (next)
|
|
907
|
-
|
|
655
|
+
else if (next) {
|
|
656
|
+
const subject = create(next);
|
|
657
|
+
const control = new Control(subject, false);
|
|
658
|
+
for (const key in control.state = next)
|
|
659
|
+
control.watch(key, {});
|
|
660
|
+
next = subject;
|
|
661
|
+
}
|
|
908
662
|
state[key] = next;
|
|
909
663
|
if (typeof argument == "function")
|
|
910
664
|
argument(next);
|
|
911
|
-
return true;
|
|
912
665
|
}
|
|
913
666
|
set(input);
|
|
914
667
|
return { set };
|
|
915
668
|
});
|
|
916
|
-
}
|
|
917
|
-
function manage(next) {
|
|
918
|
-
const subject = assign(create(next), {
|
|
919
|
-
get: getMethod,
|
|
920
|
-
set: setMethod
|
|
921
|
-
});
|
|
922
|
-
const control = new Control(subject, false);
|
|
923
|
-
for (const key in control.state = next)
|
|
924
|
-
control.watch(key, {});
|
|
925
|
-
return subject;
|
|
926
669
|
}
|
|
927
670
|
|
|
928
|
-
const Oops = issues({
|
|
929
|
-
MultipleExist: (name) => `Did find ${name} in context, but multiple were defined.`
|
|
930
|
-
});
|
|
931
671
|
class Context {
|
|
932
672
|
constructor() {
|
|
933
673
|
this.table = new WeakMap();
|
|
@@ -944,7 +684,7 @@ class Context {
|
|
|
944
684
|
get(Type) {
|
|
945
685
|
const result = this[this.has(Type)];
|
|
946
686
|
if (result === null)
|
|
947
|
-
throw
|
|
687
|
+
throw new Error(`Did find ${Type} in context, but multiple were defined.`);
|
|
948
688
|
return result;
|
|
949
689
|
}
|
|
950
690
|
include(inputs) {
|
|
@@ -964,15 +704,13 @@ class Context {
|
|
|
964
704
|
return this.include(inputs);
|
|
965
705
|
}
|
|
966
706
|
}
|
|
967
|
-
for (const [model] of init)
|
|
968
|
-
|
|
969
|
-
Object.values(state).forEach(value => {
|
|
707
|
+
for (const [model] of init)
|
|
708
|
+
values(control(model, true).state).forEach(value => {
|
|
970
709
|
if (parent(value) === model) {
|
|
971
710
|
this.add(value, true);
|
|
972
711
|
init.set(value, false);
|
|
973
712
|
}
|
|
974
713
|
});
|
|
975
|
-
}
|
|
976
714
|
return init;
|
|
977
715
|
}
|
|
978
716
|
add(input, implicit) {
|
|
@@ -984,7 +722,7 @@ class Context {
|
|
|
984
722
|
I = new input();
|
|
985
723
|
}
|
|
986
724
|
else {
|
|
987
|
-
I =
|
|
725
|
+
I = input;
|
|
988
726
|
T = I.constructor;
|
|
989
727
|
writable = false;
|
|
990
728
|
}
|
|
@@ -1024,7 +762,7 @@ const STATE = "__state";
|
|
|
1024
762
|
const UPDATE = "__update";
|
|
1025
763
|
const CONTROL = "__control";
|
|
1026
764
|
const PARENT = "__parent";
|
|
1027
|
-
defineProperties(Model.prototype, {
|
|
765
|
+
Object.defineProperties(Model.prototype, {
|
|
1028
766
|
[CONTROL]: {
|
|
1029
767
|
get() {
|
|
1030
768
|
return control(this);
|
|
@@ -1037,7 +775,7 @@ defineProperties(Model.prototype, {
|
|
|
1037
775
|
},
|
|
1038
776
|
[UPDATE]: {
|
|
1039
777
|
get() {
|
|
1040
|
-
return control(this).
|
|
778
|
+
return control(this).frame;
|
|
1041
779
|
}
|
|
1042
780
|
},
|
|
1043
781
|
[PARENT]: {
|