@expressive/mvc 1.0.0-beta.41 → 1.0.0-beta.44
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 +21 -4
- package/lib/index.esm.js +359 -339
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +359 -339
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -25,7 +25,7 @@ function issues(register) {
|
|
|
25
25
|
return Library;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
const Oops$
|
|
28
|
+
const Oops$c = issues({
|
|
29
29
|
BadEffectCallback: () => `Callback for effect-callback may only return a function.`
|
|
30
30
|
});
|
|
31
31
|
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
@@ -42,9 +42,6 @@ function defineLazy(object, property, init) {
|
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
}
|
|
45
|
-
function setAlias(func, displayName) {
|
|
46
|
-
assign(func, { displayName });
|
|
47
|
-
}
|
|
48
45
|
function createEffect(callback) {
|
|
49
46
|
let unSet;
|
|
50
47
|
return function (value) {
|
|
@@ -54,7 +51,7 @@ function createEffect(callback) {
|
|
|
54
51
|
if (unSet instanceof Promise)
|
|
55
52
|
unSet = undefined;
|
|
56
53
|
if (unSet && typeof unSet !== "function")
|
|
57
|
-
throw Oops$
|
|
54
|
+
throw Oops$c.BadEffectCallback();
|
|
58
55
|
};
|
|
59
56
|
}
|
|
60
57
|
function createValueEffect(callback) {
|
|
@@ -70,8 +67,28 @@ function createValueEffect(callback) {
|
|
|
70
67
|
if (typeof out == "function")
|
|
71
68
|
unSet = out;
|
|
72
69
|
else
|
|
73
|
-
throw Oops$
|
|
70
|
+
throw Oops$c.BadEffectCallback();
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function suspenseBoundary(fn) {
|
|
74
|
+
const retry = (err) => {
|
|
75
|
+
if (err instanceof Promise)
|
|
76
|
+
return err.then(compute);
|
|
77
|
+
else
|
|
78
|
+
throw err;
|
|
74
79
|
};
|
|
80
|
+
const compute = () => {
|
|
81
|
+
try {
|
|
82
|
+
const output = fn();
|
|
83
|
+
return output instanceof Promise
|
|
84
|
+
? output.catch(retry)
|
|
85
|
+
: output;
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
return retry(err);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
return compute();
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
const UPDATE = new WeakMap();
|
|
@@ -84,8 +101,215 @@ function applyUpdate(subject, keys) {
|
|
|
84
101
|
};
|
|
85
102
|
}
|
|
86
103
|
|
|
87
|
-
|
|
88
|
-
|
|
104
|
+
class Subscriber {
|
|
105
|
+
constructor(target, onUpdate) {
|
|
106
|
+
this.onUpdate = onUpdate;
|
|
107
|
+
this.active = false;
|
|
108
|
+
this.dependant = new Set();
|
|
109
|
+
this.watch = {};
|
|
110
|
+
const parent = target instanceof Controller
|
|
111
|
+
? target : control(target);
|
|
112
|
+
const proxy = create(parent.proxy);
|
|
113
|
+
let reset;
|
|
114
|
+
define(proxy, LOCAL, this);
|
|
115
|
+
defineProperty(this, "proxy", {
|
|
116
|
+
configurable: true,
|
|
117
|
+
get() {
|
|
118
|
+
if (reset)
|
|
119
|
+
setTimeout(reset, 0);
|
|
120
|
+
return proxy;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
const release = parent.addListener(key => {
|
|
124
|
+
const handler = this.watch[key];
|
|
125
|
+
if (!handler || !this.active)
|
|
126
|
+
return;
|
|
127
|
+
if (typeof handler == "function")
|
|
128
|
+
handler();
|
|
129
|
+
const notify = this.onUpdate(key, parent);
|
|
130
|
+
const getWhy = (keys) => {
|
|
131
|
+
reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
|
|
132
|
+
};
|
|
133
|
+
if (notify) {
|
|
134
|
+
parent.requestUpdate(getWhy);
|
|
135
|
+
parent.requestUpdate(notify);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
this.commit = () => {
|
|
139
|
+
this.active = true;
|
|
140
|
+
this.dependant.forEach(x => x.commit());
|
|
141
|
+
return this.release;
|
|
142
|
+
};
|
|
143
|
+
this.release = () => {
|
|
144
|
+
this.dependant.forEach(x => x.release());
|
|
145
|
+
release();
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const Oops$b = issues({
|
|
151
|
+
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
152
|
+
});
|
|
153
|
+
function suspend(source, key) {
|
|
154
|
+
const error = Oops$b.ValueNotReady(source.subject, key);
|
|
155
|
+
const promise = new Promise(resolve => {
|
|
156
|
+
const release = source.addListener(forKey => {
|
|
157
|
+
if (forKey == key)
|
|
158
|
+
return () => {
|
|
159
|
+
if (source.state[key] !== undefined) {
|
|
160
|
+
release();
|
|
161
|
+
resolve();
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
return Object.assign(promise, {
|
|
167
|
+
toString: () => String(error),
|
|
168
|
+
name: "Suspense",
|
|
169
|
+
message: error.message,
|
|
170
|
+
stack: error.stack
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const Oops$a = issues({
|
|
175
|
+
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
176
|
+
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
177
|
+
ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
178
|
+
ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
179
|
+
});
|
|
180
|
+
const INIT = new WeakSet();
|
|
181
|
+
const INFO = new WeakMap();
|
|
182
|
+
const USED = new WeakMap();
|
|
183
|
+
const KEYS = new WeakMap();
|
|
184
|
+
function from(source, arg1, arg2) {
|
|
185
|
+
return apply(function from(key) {
|
|
186
|
+
const parent = this;
|
|
187
|
+
const { subject, state } = this;
|
|
188
|
+
let getSource;
|
|
189
|
+
let required = arg2 === true || arg1 === true;
|
|
190
|
+
if (typeof arg1 == "boolean")
|
|
191
|
+
arg1 = undefined;
|
|
192
|
+
// Easy mistake, using a peer, will always be unresolved.
|
|
193
|
+
if (typeof source == "symbol")
|
|
194
|
+
throw Oops$a.PeerNotAllowed(subject, key);
|
|
195
|
+
// replace source controller in-case it is different
|
|
196
|
+
if (typeof source == "object")
|
|
197
|
+
getSource = () => control(source);
|
|
198
|
+
// specifically an arrow function (getter factory)
|
|
199
|
+
else if (!source.prototype) {
|
|
200
|
+
arg1 = source.call(subject, key);
|
|
201
|
+
getSource = () => this;
|
|
202
|
+
}
|
|
203
|
+
// Regular function is too ambiguous so not allowed.
|
|
204
|
+
else
|
|
205
|
+
throw Oops$a.BadComputedSource(subject, key, source);
|
|
206
|
+
let sub;
|
|
207
|
+
const setter = arg1;
|
|
208
|
+
const info = { key, parent, priority: 1 };
|
|
209
|
+
let register = USED.get(parent);
|
|
210
|
+
if (!register) {
|
|
211
|
+
register = new Map();
|
|
212
|
+
USED.set(parent, register);
|
|
213
|
+
}
|
|
214
|
+
register.set(key, info);
|
|
215
|
+
function compute(initial) {
|
|
216
|
+
try {
|
|
217
|
+
return setter.call(sub.proxy, sub.proxy);
|
|
218
|
+
}
|
|
219
|
+
catch (err) {
|
|
220
|
+
Oops$a.ComputeFailed(subject, key, !!initial).warn();
|
|
221
|
+
throw err;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function update() {
|
|
225
|
+
let value;
|
|
226
|
+
try {
|
|
227
|
+
value = compute(false);
|
|
228
|
+
}
|
|
229
|
+
catch (e) {
|
|
230
|
+
console.error(e);
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
if (state[key] !== value) {
|
|
234
|
+
parent.update(key, value);
|
|
235
|
+
return value;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
function defer(_key, from) {
|
|
240
|
+
let pending = KEYS.get(from);
|
|
241
|
+
if (!pending)
|
|
242
|
+
KEYS.set(from, pending = []);
|
|
243
|
+
if (info.parent !== from)
|
|
244
|
+
update();
|
|
245
|
+
else {
|
|
246
|
+
const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
|
|
247
|
+
pending.splice(after + 1, 0, update);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function create(early) {
|
|
251
|
+
sub = new Subscriber(getSource(), defer);
|
|
252
|
+
defineProperty(state, key, {
|
|
253
|
+
value: undefined,
|
|
254
|
+
writable: true
|
|
255
|
+
});
|
|
256
|
+
try {
|
|
257
|
+
return state[key] = compute(true);
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
if (early)
|
|
261
|
+
Oops$a.ComputedEarly(key).warn();
|
|
262
|
+
throw e;
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
sub.commit();
|
|
266
|
+
for (const key in sub.watch) {
|
|
267
|
+
const peer = register.get(key);
|
|
268
|
+
if (peer && peer.priority >= info.priority)
|
|
269
|
+
info.priority = peer.priority + 1;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
INIT.add(create);
|
|
274
|
+
INFO.set(update, info);
|
|
275
|
+
defineProperty(state, key, {
|
|
276
|
+
get: create,
|
|
277
|
+
configurable: true,
|
|
278
|
+
enumerable: true
|
|
279
|
+
});
|
|
280
|
+
return () => {
|
|
281
|
+
const value = parent.state[key];
|
|
282
|
+
if (value === undefined && required)
|
|
283
|
+
throw suspend(this, key);
|
|
284
|
+
return value;
|
|
285
|
+
};
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
function ensure(on, keys) {
|
|
289
|
+
for (const key of keys) {
|
|
290
|
+
const desc = getOwnPropertyDescriptor(on.state, key);
|
|
291
|
+
const getter = desc && desc.get;
|
|
292
|
+
if (INIT.has(getter))
|
|
293
|
+
getter(true);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function flush(on) {
|
|
297
|
+
const handled = on.frame;
|
|
298
|
+
const pending = KEYS.get(on);
|
|
299
|
+
if (!pending)
|
|
300
|
+
return;
|
|
301
|
+
while (pending.length) {
|
|
302
|
+
const why = [...handled];
|
|
303
|
+
const compute = pending.shift();
|
|
304
|
+
const { key } = INFO.get(compute);
|
|
305
|
+
if (!handled.has(key))
|
|
306
|
+
compute(why);
|
|
307
|
+
}
|
|
308
|
+
KEYS.delete(on);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const Oops$9 = issues({
|
|
312
|
+
StrictUpdate: () => `Strict update() did not find pending updates.`,
|
|
89
313
|
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
90
314
|
});
|
|
91
315
|
const READY = new WeakSet();
|
|
@@ -115,7 +339,9 @@ class Controller {
|
|
|
115
339
|
return;
|
|
116
340
|
let onGet;
|
|
117
341
|
let onSet;
|
|
342
|
+
let set;
|
|
118
343
|
let enumerable;
|
|
344
|
+
let suspense;
|
|
119
345
|
const instruction = Pending.get(entry);
|
|
120
346
|
if (instruction) {
|
|
121
347
|
Pending.delete(entry);
|
|
@@ -128,33 +354,35 @@ class Controller {
|
|
|
128
354
|
state[key] = desc.value;
|
|
129
355
|
onSet = desc.set;
|
|
130
356
|
onGet = desc.get;
|
|
357
|
+
suspense = desc.suspense;
|
|
131
358
|
enumerable = desc.enumerable;
|
|
132
359
|
}
|
|
133
360
|
}
|
|
134
361
|
else
|
|
135
362
|
state[key] = entry;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
363
|
+
if (onSet !== false)
|
|
364
|
+
set = this.ref(key, onSet);
|
|
365
|
+
const get = (local) => {
|
|
366
|
+
if (!(key in state) && suspense)
|
|
367
|
+
throw suspend(this, key);
|
|
141
368
|
const value = state[key];
|
|
142
|
-
if (
|
|
143
|
-
local
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
369
|
+
if (onGet)
|
|
370
|
+
return local
|
|
371
|
+
? onGet(value, local)
|
|
372
|
+
: onGet(value);
|
|
373
|
+
return value;
|
|
374
|
+
};
|
|
147
375
|
defineProperty(subject, key, {
|
|
148
|
-
enumerable,
|
|
149
|
-
set,
|
|
150
|
-
get: onGet
|
|
151
|
-
? () => onGet(state[key])
|
|
152
|
-
: () => state[key]
|
|
376
|
+
enumerable, set, get
|
|
153
377
|
});
|
|
154
378
|
defineProperty(proxy, key, {
|
|
155
|
-
enumerable,
|
|
156
|
-
|
|
157
|
-
|
|
379
|
+
enumerable, set,
|
|
380
|
+
get() {
|
|
381
|
+
const local = this[LOCAL];
|
|
382
|
+
if (local && !local.watch[key])
|
|
383
|
+
local.watch[key] = true;
|
|
384
|
+
return get(local);
|
|
385
|
+
}
|
|
158
386
|
});
|
|
159
387
|
}
|
|
160
388
|
ref(key, handler) {
|
|
@@ -214,17 +442,17 @@ class Controller {
|
|
|
214
442
|
this.waiting.add(arg);
|
|
215
443
|
return;
|
|
216
444
|
}
|
|
217
|
-
if (
|
|
218
|
-
return Promise.reject(Oops$
|
|
445
|
+
if (arg === true && this.frame.size < 1)
|
|
446
|
+
return Promise.reject(Oops$9.StrictUpdate());
|
|
219
447
|
return {
|
|
220
448
|
then: (callback) => {
|
|
221
449
|
if (callback)
|
|
222
|
-
if (this.frame.size)
|
|
450
|
+
if (this.frame.size || arg !== false)
|
|
223
451
|
this.waiting.add(callback);
|
|
224
452
|
else
|
|
225
453
|
callback(false);
|
|
226
454
|
else
|
|
227
|
-
throw Oops$
|
|
455
|
+
throw Oops$9.NoChaining();
|
|
228
456
|
}
|
|
229
457
|
};
|
|
230
458
|
}
|
|
@@ -253,164 +481,6 @@ function control(subject, cb) {
|
|
|
253
481
|
return cb(control);
|
|
254
482
|
}
|
|
255
483
|
|
|
256
|
-
class Subscriber {
|
|
257
|
-
constructor(target, onUpdate) {
|
|
258
|
-
this.onUpdate = onUpdate;
|
|
259
|
-
this.active = false;
|
|
260
|
-
this.dependant = new Set();
|
|
261
|
-
this.watch = {};
|
|
262
|
-
const parent = target instanceof Controller
|
|
263
|
-
? target : control(target);
|
|
264
|
-
const proxy = create(parent.proxy);
|
|
265
|
-
let reset;
|
|
266
|
-
define(proxy, LOCAL, this);
|
|
267
|
-
defineProperty(this, "proxy", {
|
|
268
|
-
configurable: true,
|
|
269
|
-
get() {
|
|
270
|
-
if (reset)
|
|
271
|
-
setTimeout(reset, 0);
|
|
272
|
-
return proxy;
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
const release = parent.addListener(key => {
|
|
276
|
-
const handler = this.watch[key];
|
|
277
|
-
if (!handler || !this.active)
|
|
278
|
-
return;
|
|
279
|
-
if (typeof handler == "function")
|
|
280
|
-
handler();
|
|
281
|
-
const notify = this.onUpdate(key, parent);
|
|
282
|
-
const getWhy = (keys) => {
|
|
283
|
-
reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
|
|
284
|
-
};
|
|
285
|
-
if (notify) {
|
|
286
|
-
parent.requestUpdate(getWhy);
|
|
287
|
-
parent.requestUpdate(notify);
|
|
288
|
-
}
|
|
289
|
-
});
|
|
290
|
-
this.commit = () => {
|
|
291
|
-
this.active = true;
|
|
292
|
-
this.dependant.forEach(x => x.commit());
|
|
293
|
-
return this.release;
|
|
294
|
-
};
|
|
295
|
-
this.release = () => {
|
|
296
|
-
this.dependant.forEach(x => x.release());
|
|
297
|
-
release();
|
|
298
|
-
};
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const Oops$b = issues({
|
|
303
|
-
ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
304
|
-
ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
305
|
-
});
|
|
306
|
-
const INIT = new WeakSet();
|
|
307
|
-
const INFO = new WeakMap();
|
|
308
|
-
const USED = new WeakMap();
|
|
309
|
-
const KEYS = new WeakMap();
|
|
310
|
-
function prepare(parent, key, source, setter, getter) {
|
|
311
|
-
let sub;
|
|
312
|
-
const { state, subject } = parent;
|
|
313
|
-
const info = { key, parent, priority: 1 };
|
|
314
|
-
let register = USED.get(parent);
|
|
315
|
-
if (!register) {
|
|
316
|
-
register = new Map();
|
|
317
|
-
USED.set(parent, register);
|
|
318
|
-
}
|
|
319
|
-
register.set(key, info);
|
|
320
|
-
function compute(initial) {
|
|
321
|
-
try {
|
|
322
|
-
return setter.call(sub.proxy, sub.proxy);
|
|
323
|
-
}
|
|
324
|
-
catch (err) {
|
|
325
|
-
Oops$b.ComputeFailed(subject, key, !!initial).warn();
|
|
326
|
-
throw err;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
function update() {
|
|
330
|
-
let value;
|
|
331
|
-
try {
|
|
332
|
-
value = compute(false);
|
|
333
|
-
}
|
|
334
|
-
catch (e) {
|
|
335
|
-
console.error(e);
|
|
336
|
-
}
|
|
337
|
-
finally {
|
|
338
|
-
if (state[key] !== value) {
|
|
339
|
-
parent.update(key, value);
|
|
340
|
-
return value;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
function defer(_key, from) {
|
|
345
|
-
let pending = KEYS.get(from);
|
|
346
|
-
if (!pending)
|
|
347
|
-
KEYS.set(from, pending = []);
|
|
348
|
-
if (info.parent !== from)
|
|
349
|
-
update();
|
|
350
|
-
else {
|
|
351
|
-
const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
|
|
352
|
-
pending.splice(after + 1, 0, update);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
function create(early) {
|
|
356
|
-
sub = new Subscriber(source(), defer);
|
|
357
|
-
defineProperty(state, key, {
|
|
358
|
-
value: undefined,
|
|
359
|
-
writable: true
|
|
360
|
-
});
|
|
361
|
-
try {
|
|
362
|
-
return state[key] = compute(true);
|
|
363
|
-
}
|
|
364
|
-
catch (e) {
|
|
365
|
-
if (early)
|
|
366
|
-
Oops$b.ComputedEarly(key).warn();
|
|
367
|
-
throw e;
|
|
368
|
-
}
|
|
369
|
-
finally {
|
|
370
|
-
sub.commit();
|
|
371
|
-
for (const key in sub.watch) {
|
|
372
|
-
const peer = register.get(key);
|
|
373
|
-
if (peer && peer.priority >= info.priority)
|
|
374
|
-
info.priority = peer.priority + 1;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
setAlias(update, `try ${key}`);
|
|
379
|
-
setAlias(create, `new ${key}`);
|
|
380
|
-
setAlias(setter, `run ${key}`);
|
|
381
|
-
INIT.add(create);
|
|
382
|
-
INFO.set(update, info);
|
|
383
|
-
defineProperty(state, key, {
|
|
384
|
-
get: create,
|
|
385
|
-
configurable: true,
|
|
386
|
-
enumerable: true
|
|
387
|
-
});
|
|
388
|
-
if (getter)
|
|
389
|
-
return () => getter(parent, key);
|
|
390
|
-
}
|
|
391
|
-
function ensure(on, keys) {
|
|
392
|
-
for (const key of keys) {
|
|
393
|
-
const desc = getOwnPropertyDescriptor(on.state, key);
|
|
394
|
-
const getter = desc && desc.get;
|
|
395
|
-
if (INIT.has(getter))
|
|
396
|
-
getter(true);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
function flush(on) {
|
|
400
|
-
const handled = on.frame;
|
|
401
|
-
const pending = KEYS.get(on);
|
|
402
|
-
if (!pending)
|
|
403
|
-
return;
|
|
404
|
-
while (pending.length) {
|
|
405
|
-
const why = [...handled];
|
|
406
|
-
const compute = pending.shift();
|
|
407
|
-
const { key } = INFO.get(compute);
|
|
408
|
-
if (!handled.has(key))
|
|
409
|
-
compute(why);
|
|
410
|
-
}
|
|
411
|
-
KEYS.delete(on);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
484
|
const CONTROL = Symbol("CONTROL");
|
|
415
485
|
const WHY = Symbol("UPDATE");
|
|
416
486
|
const LOCAL = Symbol("LOCAL");
|
|
@@ -560,17 +630,21 @@ function apply(fn, label) {
|
|
|
560
630
|
const placeholder = Symbol(`${name} instruction`);
|
|
561
631
|
function setup(key) {
|
|
562
632
|
let output = fn.call(this, key, this);
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
633
|
+
switch (typeof output) {
|
|
634
|
+
case "function":
|
|
635
|
+
return { get: output };
|
|
636
|
+
case "object": {
|
|
637
|
+
if ("explicit" in output && output.explicit) {
|
|
638
|
+
defineProperty(this.subject, key, output);
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
if ("recursive" in output && output.recursive)
|
|
642
|
+
return Object.assign(Object.assign({}, output), { get: recursive(this, key) });
|
|
643
|
+
}
|
|
644
|
+
case "boolean":
|
|
645
|
+
return output;
|
|
570
646
|
}
|
|
571
|
-
|
|
572
|
-
output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
|
|
573
|
-
return output;
|
|
647
|
+
return;
|
|
574
648
|
}
|
|
575
649
|
Pending.set(placeholder, setup);
|
|
576
650
|
return placeholder;
|
|
@@ -607,7 +681,7 @@ function recursive(source, key) {
|
|
|
607
681
|
};
|
|
608
682
|
}
|
|
609
683
|
|
|
610
|
-
const Oops$
|
|
684
|
+
const Oops$8 = issues({
|
|
611
685
|
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
|
|
612
686
|
});
|
|
613
687
|
function act(task) {
|
|
@@ -615,7 +689,7 @@ function act(task) {
|
|
|
615
689
|
let pending = false;
|
|
616
690
|
const invoke = (...args) => {
|
|
617
691
|
if (pending)
|
|
618
|
-
return Promise.reject(Oops$
|
|
692
|
+
return Promise.reject(Oops$8.DuplicateAction(key));
|
|
619
693
|
pending = true;
|
|
620
694
|
this.update(key);
|
|
621
695
|
return new Promise(res => {
|
|
@@ -626,7 +700,6 @@ function act(task) {
|
|
|
626
700
|
});
|
|
627
701
|
};
|
|
628
702
|
this.state[key] = undefined;
|
|
629
|
-
setAlias(invoke, `run ${key}`);
|
|
630
703
|
defineProperty(invoke, "active", {
|
|
631
704
|
get: () => pending
|
|
632
705
|
});
|
|
@@ -637,107 +710,6 @@ function act(task) {
|
|
|
637
710
|
});
|
|
638
711
|
}
|
|
639
712
|
|
|
640
|
-
const Oops$9 = issues({
|
|
641
|
-
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
642
|
-
});
|
|
643
|
-
/**
|
|
644
|
-
* Get value, suspend instead if undefined.
|
|
645
|
-
*
|
|
646
|
-
* Throws suspense promise also interpretable as an error.
|
|
647
|
-
* React could handle it but other contexts probably not.
|
|
648
|
-
*/
|
|
649
|
-
function pendingValue(via, key) {
|
|
650
|
-
const value = via.state[key];
|
|
651
|
-
if (value === undefined)
|
|
652
|
-
throw suspend(via, key);
|
|
653
|
-
return value;
|
|
654
|
-
}
|
|
655
|
-
function pendingFactory(via, key, fn) {
|
|
656
|
-
const { subject, state } = via;
|
|
657
|
-
let waiting;
|
|
658
|
-
let error;
|
|
659
|
-
return () => {
|
|
660
|
-
if (waiting)
|
|
661
|
-
throw waiting;
|
|
662
|
-
if (error)
|
|
663
|
-
throw error;
|
|
664
|
-
if (key in state)
|
|
665
|
-
return state[key];
|
|
666
|
-
let output;
|
|
667
|
-
try {
|
|
668
|
-
output = fn.call(subject, key, subject);
|
|
669
|
-
}
|
|
670
|
-
catch (err) {
|
|
671
|
-
throw error = err;
|
|
672
|
-
}
|
|
673
|
-
if (output instanceof Promise) {
|
|
674
|
-
const issue = Oops$9.ValueNotReady(subject, key);
|
|
675
|
-
output
|
|
676
|
-
.catch(err => error = err)
|
|
677
|
-
.then(out => state[key] = out)
|
|
678
|
-
.finally(() => waiting = undefined);
|
|
679
|
-
throw waiting = Object.assign(output, {
|
|
680
|
-
message: issue.message,
|
|
681
|
-
stack: issue.stack
|
|
682
|
-
});
|
|
683
|
-
}
|
|
684
|
-
else {
|
|
685
|
-
return state[key] = output;
|
|
686
|
-
}
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
function suspend(source, key) {
|
|
690
|
-
const error = Oops$9.ValueNotReady(source.subject, key);
|
|
691
|
-
const promise = new Promise(resolve => {
|
|
692
|
-
const release = source.addListener(forKey => {
|
|
693
|
-
if (forKey == key)
|
|
694
|
-
return () => {
|
|
695
|
-
if (source.state[key] !== undefined) {
|
|
696
|
-
release();
|
|
697
|
-
resolve();
|
|
698
|
-
}
|
|
699
|
-
};
|
|
700
|
-
});
|
|
701
|
-
});
|
|
702
|
-
return Object.assign(promise, {
|
|
703
|
-
toString: () => String(error),
|
|
704
|
-
name: "Suspense",
|
|
705
|
-
message: error.message,
|
|
706
|
-
stack: error.stack
|
|
707
|
-
});
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
const Oops$8 = issues({
|
|
711
|
-
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
712
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
713
|
-
});
|
|
714
|
-
function from(source, setter, arg) {
|
|
715
|
-
return apply(function from(key) {
|
|
716
|
-
const { subject } = this;
|
|
717
|
-
let getSource;
|
|
718
|
-
let getter;
|
|
719
|
-
if (arg === true || setter === true)
|
|
720
|
-
getter = pendingValue;
|
|
721
|
-
if (typeof setter == "boolean")
|
|
722
|
-
setter = undefined;
|
|
723
|
-
// Easy mistake, using a peer, will always be unresolved.
|
|
724
|
-
if (typeof source == "symbol")
|
|
725
|
-
throw Oops$8.PeerNotAllowed(subject, key);
|
|
726
|
-
// replace source controller in-case it is different
|
|
727
|
-
if (typeof source == "object")
|
|
728
|
-
getSource = () => control(source);
|
|
729
|
-
// specifically an arrow function (getter factory)
|
|
730
|
-
else if (!source.prototype) {
|
|
731
|
-
setter = source.call(subject, key);
|
|
732
|
-
getSource = () => this;
|
|
733
|
-
}
|
|
734
|
-
// Regular function is too ambiguous so not allowed.
|
|
735
|
-
else
|
|
736
|
-
throw Oops$8.BadComputedSource(subject, key, source);
|
|
737
|
-
return prepare(this, key, getSource, setter, getter);
|
|
738
|
-
});
|
|
739
|
-
}
|
|
740
|
-
|
|
741
713
|
function ref(arg) {
|
|
742
714
|
return apply(function ref(key) {
|
|
743
715
|
let value = {};
|
|
@@ -763,32 +735,21 @@ function createRef(key, cb) {
|
|
|
763
735
|
const Oops$7 = issues({
|
|
764
736
|
NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
|
|
765
737
|
BadFactory: () => `Set instruction can only accept a factory or undefined.`,
|
|
738
|
+
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
766
739
|
FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
767
740
|
});
|
|
768
741
|
function set(factory, argument) {
|
|
769
742
|
return apply(function set(key) {
|
|
770
743
|
let set;
|
|
771
744
|
let get;
|
|
745
|
+
let suspense;
|
|
772
746
|
const required = argument === true || argument === undefined;
|
|
773
747
|
if (factory === undefined)
|
|
774
|
-
|
|
775
|
-
else if (typeof factory
|
|
748
|
+
suspense = true;
|
|
749
|
+
else if (typeof factory === "function")
|
|
750
|
+
get = pendingFactory(this, key, factory, required);
|
|
751
|
+
else
|
|
776
752
|
throw Oops$7.BadFactory();
|
|
777
|
-
else {
|
|
778
|
-
get = pendingFactory(this, key, factory);
|
|
779
|
-
if (required)
|
|
780
|
-
try {
|
|
781
|
-
get();
|
|
782
|
-
}
|
|
783
|
-
catch (err) {
|
|
784
|
-
if (err instanceof Promise)
|
|
785
|
-
;
|
|
786
|
-
else {
|
|
787
|
-
Oops$7.FactoryFailed(this.subject, key).warn();
|
|
788
|
-
throw err;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
753
|
if (typeof argument == "function")
|
|
793
754
|
set = createValueEffect(argument);
|
|
794
755
|
else
|
|
@@ -796,8 +757,63 @@ function set(factory, argument) {
|
|
|
796
757
|
if (value === undefined && required)
|
|
797
758
|
throw Oops$7.NonOptional(this.subject, key);
|
|
798
759
|
};
|
|
799
|
-
return {
|
|
760
|
+
return {
|
|
761
|
+
set,
|
|
762
|
+
get,
|
|
763
|
+
suspense
|
|
764
|
+
};
|
|
800
765
|
});
|
|
766
|
+
}
|
|
767
|
+
function pendingFactory(parent, key, fn, required) {
|
|
768
|
+
const { subject, state } = parent;
|
|
769
|
+
let pending;
|
|
770
|
+
let error;
|
|
771
|
+
const init = () => {
|
|
772
|
+
const output = suspenseBoundary(() => {
|
|
773
|
+
return fn.call(subject, key, subject);
|
|
774
|
+
});
|
|
775
|
+
if (output instanceof Promise) {
|
|
776
|
+
pending = output
|
|
777
|
+
.catch(err => error = err)
|
|
778
|
+
.then(val => state[key] = val)
|
|
779
|
+
.finally(() => {
|
|
780
|
+
pending = undefined;
|
|
781
|
+
parent.update(key);
|
|
782
|
+
});
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
return state[key] = output;
|
|
786
|
+
};
|
|
787
|
+
const suspend = () => {
|
|
788
|
+
if (required === false)
|
|
789
|
+
return undefined;
|
|
790
|
+
const issue = Oops$7.ValueNotReady(subject, key);
|
|
791
|
+
Object.assign(pending, {
|
|
792
|
+
message: issue.message,
|
|
793
|
+
stack: issue.stack
|
|
794
|
+
});
|
|
795
|
+
throw pending;
|
|
796
|
+
};
|
|
797
|
+
if (required)
|
|
798
|
+
try {
|
|
799
|
+
init();
|
|
800
|
+
}
|
|
801
|
+
catch (err) {
|
|
802
|
+
Oops$7.FactoryFailed(subject, key).warn();
|
|
803
|
+
throw err;
|
|
804
|
+
}
|
|
805
|
+
return () => {
|
|
806
|
+
if (pending)
|
|
807
|
+
return suspend();
|
|
808
|
+
if (error)
|
|
809
|
+
throw error;
|
|
810
|
+
if (key in state)
|
|
811
|
+
return state[key];
|
|
812
|
+
let output = init();
|
|
813
|
+
return pending
|
|
814
|
+
? suspend()
|
|
815
|
+
: output;
|
|
816
|
+
};
|
|
801
817
|
}
|
|
802
818
|
|
|
803
819
|
const Parent = new WeakMap();
|
|
@@ -940,24 +956,26 @@ const ContextWasUsed = new WeakMap();
|
|
|
940
956
|
function tap(type, argument) {
|
|
941
957
|
return apply(function tap(key) {
|
|
942
958
|
if ("set" in type)
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
+
return {
|
|
960
|
+
recursive: true,
|
|
961
|
+
value: type.get()
|
|
962
|
+
};
|
|
963
|
+
const { subject } = this;
|
|
964
|
+
if ("set" in subject.constructor)
|
|
965
|
+
throw Oops$3.CantAttachGlobal(subject, type.name);
|
|
966
|
+
getPending(subject).push(context => {
|
|
967
|
+
let instance = context.get(type);
|
|
968
|
+
if (typeof argument == "function") {
|
|
969
|
+
if (argument(instance) === false)
|
|
970
|
+
instance = undefined;
|
|
971
|
+
}
|
|
972
|
+
else if (!instance && argument)
|
|
973
|
+
throw Oops$3.AmbientRequired(type.name, subject, key);
|
|
974
|
+
this.update(key, instance);
|
|
975
|
+
});
|
|
959
976
|
return {
|
|
960
|
-
recursive: true
|
|
977
|
+
recursive: true,
|
|
978
|
+
suspense: true
|
|
961
979
|
};
|
|
962
980
|
});
|
|
963
981
|
}
|
|
@@ -1129,7 +1147,7 @@ class MVC extends Model {
|
|
|
1129
1147
|
return useTap(this, key, expect);
|
|
1130
1148
|
}
|
|
1131
1149
|
static new(arg) {
|
|
1132
|
-
|
|
1150
|
+
const instance = React__default["default"].useMemo(() => {
|
|
1133
1151
|
const instance = new this();
|
|
1134
1152
|
control(instance);
|
|
1135
1153
|
if (typeof arg == "function")
|
|
@@ -1141,6 +1159,8 @@ class MVC extends Model {
|
|
|
1141
1159
|
});
|
|
1142
1160
|
return instance;
|
|
1143
1161
|
}, []);
|
|
1162
|
+
usePeerContext(instance.get);
|
|
1163
|
+
return instance;
|
|
1144
1164
|
}
|
|
1145
1165
|
static use(a, b) {
|
|
1146
1166
|
const instance = useModel(this, a, b);
|
|
@@ -1253,7 +1273,7 @@ class Global extends MVC {
|
|
|
1253
1273
|
static set(updates) {
|
|
1254
1274
|
const instance = Active.get(this) || this.create();
|
|
1255
1275
|
instance.import(updates);
|
|
1256
|
-
return instance.update();
|
|
1276
|
+
return instance.update(false);
|
|
1257
1277
|
}
|
|
1258
1278
|
static get(arg) {
|
|
1259
1279
|
const instance = Active.get(this);
|