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