@expressive/mvc 1.0.0-beta.42 → 1.0.0-beta.45
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 +44 -37
- package/lib/index.esm.js +588 -507
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +588 -506
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
package/lib/index.esm.js
CHANGED
|
@@ -17,7 +17,7 @@ function issues(register) {
|
|
|
17
17
|
return Library;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const Oops$
|
|
20
|
+
const Oops$c = issues({
|
|
21
21
|
BadEffectCallback: () => `Callback for effect-callback may only return a function.`
|
|
22
22
|
});
|
|
23
23
|
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
@@ -34,9 +34,6 @@ function defineLazy(object, property, init) {
|
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
|
-
function setAlias(func, displayName) {
|
|
38
|
-
assign(func, { displayName });
|
|
39
|
-
}
|
|
40
37
|
function createEffect(callback) {
|
|
41
38
|
let unSet;
|
|
42
39
|
return function (value) {
|
|
@@ -46,7 +43,7 @@ function createEffect(callback) {
|
|
|
46
43
|
if (unSet instanceof Promise)
|
|
47
44
|
unSet = undefined;
|
|
48
45
|
if (unSet && typeof unSet !== "function")
|
|
49
|
-
throw Oops$
|
|
46
|
+
throw Oops$c.BadEffectCallback();
|
|
50
47
|
};
|
|
51
48
|
}
|
|
52
49
|
function createValueEffect(callback) {
|
|
@@ -62,8 +59,28 @@ function createValueEffect(callback) {
|
|
|
62
59
|
if (typeof out == "function")
|
|
63
60
|
unSet = out;
|
|
64
61
|
else
|
|
65
|
-
throw Oops$
|
|
62
|
+
throw Oops$c.BadEffectCallback();
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function suspenseBoundary(fn) {
|
|
66
|
+
const retry = (err) => {
|
|
67
|
+
if (err instanceof Promise)
|
|
68
|
+
return err.then(compute);
|
|
69
|
+
else
|
|
70
|
+
throw err;
|
|
71
|
+
};
|
|
72
|
+
const compute = () => {
|
|
73
|
+
try {
|
|
74
|
+
const output = fn();
|
|
75
|
+
return output instanceof Promise
|
|
76
|
+
? output.catch(retry)
|
|
77
|
+
: output;
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
return retry(err);
|
|
81
|
+
}
|
|
66
82
|
};
|
|
83
|
+
return compute();
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
const UPDATE = new WeakMap();
|
|
@@ -76,174 +93,148 @@ function applyUpdate(subject, keys) {
|
|
|
76
93
|
};
|
|
77
94
|
}
|
|
78
95
|
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this
|
|
87
|
-
this
|
|
88
|
-
this.frame = new Set();
|
|
89
|
-
this.waiting = new Set();
|
|
90
|
-
this.onDestroy = new Set();
|
|
91
|
-
this.followers = new Set();
|
|
92
|
-
this.proxy = Object.create(subject);
|
|
96
|
+
const CONTROL = Symbol("CONTROL");
|
|
97
|
+
const WHY = Symbol("UPDATE");
|
|
98
|
+
const LOCAL = Symbol("LOCAL");
|
|
99
|
+
const STATE = Symbol("STATE");
|
|
100
|
+
class Model {
|
|
101
|
+
constructor() {
|
|
102
|
+
define(this, CONTROL, new Controller(this));
|
|
103
|
+
define(this, "get", this);
|
|
104
|
+
define(this, "set", this);
|
|
93
105
|
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
this.manage(key);
|
|
97
|
-
this.emit([]);
|
|
106
|
+
get [STATE]() {
|
|
107
|
+
return this[CONTROL].state;
|
|
98
108
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.onDestroy.forEach(x => x());
|
|
109
|
+
get [WHY]() {
|
|
110
|
+
return UPDATE.get(this);
|
|
102
111
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else
|
|
127
|
-
state[key] = entry;
|
|
128
|
-
const set = onSet !== false
|
|
129
|
-
? this.ref(key, onSet)
|
|
130
|
-
: undefined;
|
|
131
|
-
function get() {
|
|
132
|
-
const local = this[LOCAL];
|
|
133
|
-
const value = state[key];
|
|
134
|
-
if (local && !local.watch[key])
|
|
135
|
-
local.watch[key] = true;
|
|
136
|
-
return onGet ? onGet(value, local) : value;
|
|
137
|
-
}
|
|
138
|
-
setAlias(get, `tap ${key}`);
|
|
139
|
-
defineProperty(subject, key, {
|
|
140
|
-
enumerable,
|
|
141
|
-
set,
|
|
142
|
-
get: onGet
|
|
143
|
-
? () => onGet(state[key])
|
|
144
|
-
: () => state[key]
|
|
145
|
-
});
|
|
146
|
-
defineProperty(proxy, key, {
|
|
147
|
-
enumerable,
|
|
148
|
-
set,
|
|
149
|
-
get
|
|
112
|
+
on(select, handler, squash, once) {
|
|
113
|
+
return control(this, control => {
|
|
114
|
+
if (typeof select == "function")
|
|
115
|
+
return control.addListener(select);
|
|
116
|
+
const keys = typeof select == "string" ? [select] :
|
|
117
|
+
!select.length ? getOwnPropertyNames(control.state) :
|
|
118
|
+
select;
|
|
119
|
+
ensure(control, keys);
|
|
120
|
+
const callback = squash
|
|
121
|
+
? handler.bind(this)
|
|
122
|
+
: frame => frame
|
|
123
|
+
.filter(k => keys.includes(k))
|
|
124
|
+
.forEach(k => handler.call(this, control.state[k], k));
|
|
125
|
+
const trigger = once
|
|
126
|
+
? frame => { remove(); callback(frame); }
|
|
127
|
+
: callback;
|
|
128
|
+
const remove = control.addListener(key => {
|
|
129
|
+
if (keys.includes(key))
|
|
130
|
+
return trigger;
|
|
131
|
+
});
|
|
132
|
+
return remove;
|
|
150
133
|
});
|
|
151
134
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
switch (handler.call(subject, value, state)) {
|
|
159
|
-
case true:
|
|
160
|
-
this.update(key);
|
|
161
|
-
case false:
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
this.update(key, value);
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
addListener(listener) {
|
|
168
|
-
this.followers.add(listener);
|
|
169
|
-
return () => {
|
|
170
|
-
this.followers.delete(listener);
|
|
171
|
-
};
|
|
135
|
+
once(select, callback, squash) {
|
|
136
|
+
if (callback)
|
|
137
|
+
return this.on(select, callback, squash, true);
|
|
138
|
+
return new Promise(resolve => {
|
|
139
|
+
this.on(select, resolve, true, true);
|
|
140
|
+
});
|
|
172
141
|
}
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
this
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
142
|
+
effect(callback, select) {
|
|
143
|
+
const effect = createEffect(callback);
|
|
144
|
+
return control(this, control => {
|
|
145
|
+
if (!select) {
|
|
146
|
+
const sub = new Subscriber(control, () => invoke);
|
|
147
|
+
const invoke = () => {
|
|
148
|
+
const x = sub.proxy;
|
|
149
|
+
effect.call(x, x);
|
|
150
|
+
};
|
|
151
|
+
invoke();
|
|
152
|
+
return sub.commit();
|
|
180
153
|
}
|
|
181
|
-
|
|
182
|
-
|
|
154
|
+
const invoke = () => {
|
|
155
|
+
effect.call(this.get, this.get);
|
|
156
|
+
};
|
|
157
|
+
invoke();
|
|
158
|
+
if (!select.length) {
|
|
159
|
+
control.onDestroy.add(invoke);
|
|
160
|
+
return () => {
|
|
161
|
+
control.onDestroy.delete(invoke);
|
|
162
|
+
};
|
|
183
163
|
}
|
|
164
|
+
return control.addListener(key => {
|
|
165
|
+
if (select.includes(key))
|
|
166
|
+
return invoke;
|
|
167
|
+
});
|
|
168
|
+
});
|
|
184
169
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const keys = Object.freeze([...this.frame]);
|
|
194
|
-
this.frame.clear();
|
|
195
|
-
this.emit(keys);
|
|
196
|
-
}, 0);
|
|
197
|
-
this.frame.add(key);
|
|
198
|
-
for (const callback of this.followers) {
|
|
199
|
-
const event = callback(key, this);
|
|
200
|
-
if (typeof event == "function")
|
|
201
|
-
this.waiting.add(event);
|
|
202
|
-
}
|
|
170
|
+
// TODO: account for exotic properties
|
|
171
|
+
import(source, select) {
|
|
172
|
+
const { subject } = control(this);
|
|
173
|
+
if (!select)
|
|
174
|
+
select = getOwnPropertyNames(subject);
|
|
175
|
+
for (const key of select)
|
|
176
|
+
if (key in source)
|
|
177
|
+
this[key] = source[key];
|
|
203
178
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
return
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
179
|
+
export(subset) {
|
|
180
|
+
const { state } = control(this);
|
|
181
|
+
const output = {};
|
|
182
|
+
if (!subset)
|
|
183
|
+
subset = getOwnPropertyNames(state);
|
|
184
|
+
for (const key of subset)
|
|
185
|
+
output[key] = state[key];
|
|
186
|
+
return output;
|
|
187
|
+
}
|
|
188
|
+
update(arg, tag) {
|
|
189
|
+
const target = control(this);
|
|
190
|
+
if (typeof arg == "string") {
|
|
191
|
+
target.update(arg);
|
|
192
|
+
if (1 in arguments && arg in this) {
|
|
193
|
+
const method = this[arg];
|
|
194
|
+
if (typeof method == "function")
|
|
195
|
+
if (typeof tag != "boolean")
|
|
196
|
+
method.call(this, tag);
|
|
197
|
+
else if (tag)
|
|
198
|
+
method.call(this);
|
|
220
199
|
}
|
|
221
|
-
|
|
200
|
+
arg = undefined;
|
|
201
|
+
}
|
|
202
|
+
return target.requestUpdate(arg);
|
|
222
203
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
control = new Controller(subject);
|
|
229
|
-
define(subject, CONTROL, control);
|
|
204
|
+
/**
|
|
205
|
+
* Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
|
|
206
|
+
*/
|
|
207
|
+
destroy() {
|
|
208
|
+
control(this).stop();
|
|
230
209
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
READY.add(control);
|
|
234
|
-
control.start();
|
|
235
|
-
}
|
|
236
|
-
return control;
|
|
210
|
+
toString() {
|
|
211
|
+
return this.constructor.name;
|
|
237
212
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
213
|
+
/**
|
|
214
|
+
* Creates a new instance of this controller.
|
|
215
|
+
*
|
|
216
|
+
* Beyond `new this(...)`, method will activate managed-state.
|
|
217
|
+
*
|
|
218
|
+
* @param args - arguments sent to constructor
|
|
219
|
+
*/
|
|
220
|
+
static create(...args) {
|
|
221
|
+
const instance = new this(...args);
|
|
222
|
+
control(instance);
|
|
223
|
+
return instance;
|
|
244
224
|
}
|
|
245
|
-
|
|
246
|
-
|
|
225
|
+
/**
|
|
226
|
+
* Static equivalent of `x instanceof this`.
|
|
227
|
+
*
|
|
228
|
+
* Will determine if provided class is a subtype of this one.
|
|
229
|
+
*/
|
|
230
|
+
static isTypeof(maybe) {
|
|
231
|
+
return (typeof maybe == "function" &&
|
|
232
|
+
maybe.prototype instanceof this);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
defineLazy(Model, CONTROL, function () {
|
|
236
|
+
return new Controller(this);
|
|
237
|
+
});
|
|
247
238
|
|
|
248
239
|
class Subscriber {
|
|
249
240
|
constructor(target, onUpdate) {
|
|
@@ -292,6 +283,32 @@ class Subscriber {
|
|
|
292
283
|
}
|
|
293
284
|
|
|
294
285
|
const Oops$b = issues({
|
|
286
|
+
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
287
|
+
});
|
|
288
|
+
function suspend(source, key) {
|
|
289
|
+
const error = Oops$b.ValueNotReady(source.subject, key);
|
|
290
|
+
const promise = new Promise(resolve => {
|
|
291
|
+
const release = source.addListener(forKey => {
|
|
292
|
+
if (forKey == key)
|
|
293
|
+
return () => {
|
|
294
|
+
if (source.state[key] !== undefined) {
|
|
295
|
+
release();
|
|
296
|
+
resolve();
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
return Object.assign(promise, {
|
|
302
|
+
toString: () => String(error),
|
|
303
|
+
name: "Suspense",
|
|
304
|
+
message: error.message,
|
|
305
|
+
stack: error.stack
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const Oops$a = issues({
|
|
310
|
+
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
311
|
+
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
|
|
295
312
|
ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
296
313
|
ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
297
314
|
});
|
|
@@ -299,86 +316,109 @@ const INIT = new WeakSet();
|
|
|
299
316
|
const INFO = new WeakMap();
|
|
300
317
|
const USED = new WeakMap();
|
|
301
318
|
const KEYS = new WeakMap();
|
|
302
|
-
function
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
319
|
+
function from(source, arg1, arg2) {
|
|
320
|
+
return apply(function from(key) {
|
|
321
|
+
const parent = this;
|
|
322
|
+
const { subject, state } = this;
|
|
323
|
+
let getSource;
|
|
324
|
+
let required = arg2 === true || arg1 === true;
|
|
325
|
+
if (typeof arg1 == "boolean")
|
|
326
|
+
arg1 = undefined;
|
|
327
|
+
// Easy mistake, using a peer, will always be unresolved.
|
|
328
|
+
if (typeof source == "symbol")
|
|
329
|
+
throw Oops$a.PeerNotAllowed(subject, key);
|
|
330
|
+
// replace source controller in-case it is different
|
|
331
|
+
if (typeof source == "object")
|
|
332
|
+
getSource = () => control(source);
|
|
333
|
+
// specifically an arrow function (getter factory)
|
|
334
|
+
else if (!source.prototype) {
|
|
335
|
+
arg1 = source.call(subject, key);
|
|
336
|
+
getSource = () => this;
|
|
315
337
|
}
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
throw
|
|
338
|
+
// Regular function is too ambiguous so not allowed.
|
|
339
|
+
else
|
|
340
|
+
throw Oops$a.BadComputedSource(subject, key, source);
|
|
341
|
+
let sub;
|
|
342
|
+
const setter = arg1;
|
|
343
|
+
const info = { key, parent, priority: 1 };
|
|
344
|
+
let register = USED.get(parent);
|
|
345
|
+
if (!register) {
|
|
346
|
+
register = new Map();
|
|
347
|
+
USED.set(parent, register);
|
|
319
348
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
349
|
+
register.set(key, info);
|
|
350
|
+
function compute(initial) {
|
|
351
|
+
try {
|
|
352
|
+
return setter.call(sub.proxy, sub.proxy);
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
Oops$a.ComputeFailed(subject, key, !!initial).warn();
|
|
356
|
+
throw err;
|
|
357
|
+
}
|
|
325
358
|
}
|
|
326
|
-
|
|
327
|
-
|
|
359
|
+
function update() {
|
|
360
|
+
let value;
|
|
361
|
+
try {
|
|
362
|
+
value = compute(false);
|
|
363
|
+
}
|
|
364
|
+
catch (e) {
|
|
365
|
+
console.error(e);
|
|
366
|
+
}
|
|
367
|
+
finally {
|
|
368
|
+
if (state[key] !== value) {
|
|
369
|
+
parent.update(key, value);
|
|
370
|
+
return value;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
328
373
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
374
|
+
function defer(_key, from) {
|
|
375
|
+
let pending = KEYS.get(from);
|
|
376
|
+
if (!pending)
|
|
377
|
+
KEYS.set(from, pending = []);
|
|
378
|
+
if (info.parent !== from)
|
|
379
|
+
update();
|
|
380
|
+
else {
|
|
381
|
+
const after = pending.findIndex(peer => (info.priority > INFO.get(peer).priority));
|
|
382
|
+
pending.splice(after + 1, 0, update);
|
|
333
383
|
}
|
|
334
384
|
}
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
385
|
+
function create(early) {
|
|
386
|
+
sub = new Subscriber(getSource(), defer);
|
|
387
|
+
defineProperty(state, key, {
|
|
388
|
+
value: undefined,
|
|
389
|
+
writable: true
|
|
390
|
+
});
|
|
391
|
+
try {
|
|
392
|
+
return state[key] = compute(true);
|
|
393
|
+
}
|
|
394
|
+
catch (e) {
|
|
395
|
+
if (early)
|
|
396
|
+
Oops$a.ComputedEarly(key).warn();
|
|
397
|
+
throw e;
|
|
398
|
+
}
|
|
399
|
+
finally {
|
|
400
|
+
sub.commit();
|
|
401
|
+
for (const key in sub.watch) {
|
|
402
|
+
const peer = register.get(key);
|
|
403
|
+
if (peer && peer.priority >= info.priority)
|
|
404
|
+
info.priority = peer.priority + 1;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
345
407
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
sub = new Subscriber(source(), defer);
|
|
408
|
+
INIT.add(create);
|
|
409
|
+
INFO.set(update, info);
|
|
349
410
|
defineProperty(state, key, {
|
|
350
|
-
|
|
351
|
-
|
|
411
|
+
get: create,
|
|
412
|
+
configurable: true,
|
|
413
|
+
enumerable: true
|
|
352
414
|
});
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
throw e;
|
|
360
|
-
}
|
|
361
|
-
finally {
|
|
362
|
-
sub.commit();
|
|
363
|
-
for (const key in sub.watch) {
|
|
364
|
-
const peer = register.get(key);
|
|
365
|
-
if (peer && peer.priority >= info.priority)
|
|
366
|
-
info.priority = peer.priority + 1;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
setAlias(update, `try ${key}`);
|
|
371
|
-
setAlias(create, `new ${key}`);
|
|
372
|
-
setAlias(setter, `run ${key}`);
|
|
373
|
-
INIT.add(create);
|
|
374
|
-
INFO.set(update, info);
|
|
375
|
-
defineProperty(state, key, {
|
|
376
|
-
get: create,
|
|
377
|
-
configurable: true,
|
|
378
|
-
enumerable: true
|
|
415
|
+
return () => {
|
|
416
|
+
const value = parent.state[key];
|
|
417
|
+
if (value === undefined && required)
|
|
418
|
+
throw suspend(this, key);
|
|
419
|
+
return value;
|
|
420
|
+
};
|
|
379
421
|
});
|
|
380
|
-
if (getter)
|
|
381
|
-
return () => getter(parent, key);
|
|
382
422
|
}
|
|
383
423
|
function ensure(on, keys) {
|
|
384
424
|
for (const key of keys) {
|
|
@@ -403,175 +443,205 @@ function flush(on) {
|
|
|
403
443
|
KEYS.delete(on);
|
|
404
444
|
}
|
|
405
445
|
|
|
406
|
-
const
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
446
|
+
const Oops$9 = issues({
|
|
447
|
+
StrictUpdate: () => `Strict update() did not find pending updates.`,
|
|
448
|
+
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
449
|
+
});
|
|
450
|
+
const PENDING = new Map();
|
|
451
|
+
const READY = new WeakSet();
|
|
452
|
+
class Controller {
|
|
453
|
+
constructor(subject) {
|
|
454
|
+
this.subject = subject;
|
|
455
|
+
this.state = {};
|
|
456
|
+
this.frame = new Set();
|
|
457
|
+
this.waiting = new Set();
|
|
458
|
+
this.onDestroy = new Set();
|
|
459
|
+
this.followers = new Set();
|
|
460
|
+
this.proxy = Object.create(subject);
|
|
418
461
|
}
|
|
419
|
-
|
|
420
|
-
|
|
462
|
+
start() {
|
|
463
|
+
for (const key in this.subject)
|
|
464
|
+
this.manage(key);
|
|
465
|
+
this.emit([]);
|
|
421
466
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return control.addListener(select);
|
|
426
|
-
const keys = typeof select == "string" ? [select] :
|
|
427
|
-
!select.length ? getOwnPropertyNames(control.state) :
|
|
428
|
-
select;
|
|
429
|
-
ensure(control, keys);
|
|
430
|
-
const callback = squash
|
|
431
|
-
? handler.bind(this)
|
|
432
|
-
: frame => frame
|
|
433
|
-
.filter(k => keys.includes(k))
|
|
434
|
-
.forEach(k => handler.call(this, control.state[k], k));
|
|
435
|
-
const trigger = once
|
|
436
|
-
? frame => { remove(); callback(frame); }
|
|
437
|
-
: callback;
|
|
438
|
-
const remove = control.addListener(key => {
|
|
439
|
-
if (keys.includes(key))
|
|
440
|
-
return trigger;
|
|
441
|
-
});
|
|
442
|
-
return remove;
|
|
443
|
-
});
|
|
467
|
+
stop() {
|
|
468
|
+
this.followers.clear();
|
|
469
|
+
this.onDestroy.forEach(x => x());
|
|
444
470
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
471
|
+
manage(key) {
|
|
472
|
+
const { proxy, state, subject } = this;
|
|
473
|
+
const { value: entry } = getOwnPropertyDescriptor(subject, key);
|
|
474
|
+
if (typeof entry == "function")
|
|
475
|
+
return;
|
|
476
|
+
if (typeof entry == "symbol") {
|
|
477
|
+
const instruction = PENDING.get(entry);
|
|
478
|
+
if (instruction)
|
|
479
|
+
instruction.call(this, key, this);
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
state[key] = entry;
|
|
483
|
+
const set = this.ref(key);
|
|
484
|
+
defineProperty(subject, key, {
|
|
485
|
+
enumerable: false,
|
|
486
|
+
get: () => state[key],
|
|
487
|
+
set
|
|
450
488
|
});
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
};
|
|
461
|
-
invoke();
|
|
462
|
-
return sub.commit();
|
|
463
|
-
}
|
|
464
|
-
const invoke = () => {
|
|
465
|
-
effect.call(this.get, this.get);
|
|
466
|
-
};
|
|
467
|
-
invoke();
|
|
468
|
-
if (!select.length) {
|
|
469
|
-
control.onDestroy.add(invoke);
|
|
470
|
-
return () => {
|
|
471
|
-
control.onDestroy.delete(invoke);
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
return control.addListener(key => {
|
|
475
|
-
if (select.includes(key))
|
|
476
|
-
return invoke;
|
|
477
|
-
});
|
|
489
|
+
defineProperty(proxy, key, {
|
|
490
|
+
enumerable: false,
|
|
491
|
+
get() {
|
|
492
|
+
const local = this[LOCAL];
|
|
493
|
+
if (local && !local.watch[key])
|
|
494
|
+
local.watch[key] = true;
|
|
495
|
+
return state[key];
|
|
496
|
+
},
|
|
497
|
+
set
|
|
478
498
|
});
|
|
479
499
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
500
|
+
ref(key, handler) {
|
|
501
|
+
const { state, subject } = this;
|
|
502
|
+
return (value) => {
|
|
503
|
+
if (state[key] == value)
|
|
504
|
+
return;
|
|
505
|
+
if (handler)
|
|
506
|
+
switch (handler.call(subject, value, state)) {
|
|
507
|
+
case true:
|
|
508
|
+
this.update(key);
|
|
509
|
+
case false:
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
this.update(key, value);
|
|
513
|
+
};
|
|
488
514
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
for (const key of subset)
|
|
495
|
-
output[key] = state[key];
|
|
496
|
-
return output;
|
|
515
|
+
addListener(listener) {
|
|
516
|
+
this.followers.add(listener);
|
|
517
|
+
return () => {
|
|
518
|
+
this.followers.delete(listener);
|
|
519
|
+
};
|
|
497
520
|
}
|
|
498
|
-
|
|
499
|
-
const
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
if (typeof tag != "boolean")
|
|
506
|
-
method.call(this, tag);
|
|
507
|
-
else if (tag)
|
|
508
|
-
method.call(this);
|
|
521
|
+
emit(keys) {
|
|
522
|
+
const waiting = [...this.waiting];
|
|
523
|
+
this.waiting.clear();
|
|
524
|
+
applyUpdate(this.subject, keys)();
|
|
525
|
+
for (const callback of waiting)
|
|
526
|
+
try {
|
|
527
|
+
callback(keys);
|
|
509
528
|
}
|
|
510
|
-
|
|
529
|
+
catch (err) {
|
|
530
|
+
console.error(err);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
update(key, value) {
|
|
534
|
+
if (1 in arguments)
|
|
535
|
+
this.state[key] = value;
|
|
536
|
+
if (this.frame.has(key))
|
|
537
|
+
return;
|
|
538
|
+
if (!this.frame.size)
|
|
539
|
+
setTimeout(() => {
|
|
540
|
+
flush(this);
|
|
541
|
+
const keys = Object.freeze([...this.frame]);
|
|
542
|
+
this.frame.clear();
|
|
543
|
+
this.emit(keys);
|
|
544
|
+
}, 0);
|
|
545
|
+
this.frame.add(key);
|
|
546
|
+
for (const callback of this.followers) {
|
|
547
|
+
const event = callback(key, this);
|
|
548
|
+
if (typeof event == "function")
|
|
549
|
+
this.waiting.add(event);
|
|
511
550
|
}
|
|
512
|
-
return target.requestUpdate(arg);
|
|
513
551
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
552
|
+
requestUpdate(arg) {
|
|
553
|
+
if (typeof arg == "function") {
|
|
554
|
+
this.waiting.add(arg);
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (arg === true && this.frame.size < 1)
|
|
558
|
+
return Promise.reject(Oops$9.StrictUpdate());
|
|
559
|
+
return {
|
|
560
|
+
then: (callback) => {
|
|
561
|
+
if (callback)
|
|
562
|
+
if (this.frame.size || arg !== false)
|
|
563
|
+
this.waiting.add(callback);
|
|
564
|
+
else
|
|
565
|
+
callback(false);
|
|
566
|
+
else
|
|
567
|
+
throw Oops$9.NoChaining();
|
|
568
|
+
}
|
|
569
|
+
};
|
|
519
570
|
}
|
|
520
|
-
|
|
521
|
-
|
|
571
|
+
}
|
|
572
|
+
function control(subject, cb) {
|
|
573
|
+
let control = subject[CONTROL];
|
|
574
|
+
const ready = READY.has(control);
|
|
575
|
+
if (!control) {
|
|
576
|
+
control = new Controller(subject);
|
|
577
|
+
define(subject, CONTROL, control);
|
|
522
578
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
*/
|
|
530
|
-
static create(...args) {
|
|
531
|
-
const instance = new this(...args);
|
|
532
|
-
control(instance);
|
|
533
|
-
return instance;
|
|
579
|
+
if (!cb) {
|
|
580
|
+
if (!ready) {
|
|
581
|
+
READY.add(control);
|
|
582
|
+
control.start();
|
|
583
|
+
}
|
|
584
|
+
return control;
|
|
534
585
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
return (typeof maybe == "function" &&
|
|
542
|
-
maybe.prototype instanceof this);
|
|
586
|
+
if (!ready) {
|
|
587
|
+
let done;
|
|
588
|
+
control.requestUpdate(() => {
|
|
589
|
+
done = cb(control);
|
|
590
|
+
});
|
|
591
|
+
return () => done && done();
|
|
543
592
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
return new Controller(this);
|
|
547
|
-
});
|
|
593
|
+
return cb(control);
|
|
594
|
+
}
|
|
548
595
|
|
|
549
|
-
const Pending = new Map();
|
|
550
596
|
function apply(fn, label) {
|
|
551
597
|
const name = label || fn.name || "pending";
|
|
552
598
|
const placeholder = Symbol(`${name} instruction`);
|
|
553
599
|
function setup(key) {
|
|
600
|
+
const { proxy, state, subject } = this;
|
|
601
|
+
const control = this;
|
|
602
|
+
PENDING.delete(placeholder);
|
|
603
|
+
delete subject[key];
|
|
554
604
|
let output = fn.call(this, key, this);
|
|
555
605
|
if (typeof output == "function")
|
|
556
|
-
|
|
557
|
-
if (typeof output
|
|
558
|
-
return
|
|
606
|
+
output = { get: output };
|
|
607
|
+
if (typeof output != "object")
|
|
608
|
+
return;
|
|
559
609
|
if ("explicit" in output && output.explicit) {
|
|
560
|
-
defineProperty(
|
|
610
|
+
defineProperty(subject, key, output);
|
|
561
611
|
return false;
|
|
562
612
|
}
|
|
563
|
-
if ("recursive" in output)
|
|
613
|
+
if ("recursive" in output && output.recursive)
|
|
564
614
|
output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
|
|
565
|
-
|
|
615
|
+
const desc = output;
|
|
616
|
+
if ("value" in desc)
|
|
617
|
+
state[key] = desc.value;
|
|
618
|
+
const { get: onGet, set: onSet, enumerable, suspense } = desc;
|
|
619
|
+
let set = onSet === false
|
|
620
|
+
? undefined
|
|
621
|
+
: this.ref(key, onSet);
|
|
622
|
+
function get() {
|
|
623
|
+
if (!(key in state) && suspense)
|
|
624
|
+
throw suspend(control, key);
|
|
625
|
+
const local = this[LOCAL];
|
|
626
|
+
if (local && !(key in local.watch))
|
|
627
|
+
local.watch[key] = true;
|
|
628
|
+
const value = state[key];
|
|
629
|
+
if (!onGet)
|
|
630
|
+
return value;
|
|
631
|
+
return local
|
|
632
|
+
? onGet(value, local)
|
|
633
|
+
: onGet(value);
|
|
634
|
+
}
|
|
635
|
+
for (const x of [subject, proxy])
|
|
636
|
+
defineProperty(x, key, { enumerable, get, set });
|
|
566
637
|
}
|
|
567
|
-
|
|
638
|
+
PENDING.set(placeholder, setup);
|
|
568
639
|
return placeholder;
|
|
569
640
|
}
|
|
570
641
|
function recursive(source, key) {
|
|
571
|
-
|
|
572
|
-
const subscribe = (parent) => {
|
|
642
|
+
return forSubscriber((parent, context) => {
|
|
573
643
|
let child;
|
|
574
|
-
|
|
644
|
+
function init() {
|
|
575
645
|
if (child) {
|
|
576
646
|
child.release();
|
|
577
647
|
parent.dependant.delete(child);
|
|
@@ -586,20 +656,28 @@ function recursive(source, key) {
|
|
|
586
656
|
parent.dependant.add(child);
|
|
587
657
|
context.set(parent, child.proxy);
|
|
588
658
|
}
|
|
589
|
-
}
|
|
659
|
+
}
|
|
590
660
|
init();
|
|
591
661
|
parent.watch[key] = init;
|
|
592
|
-
};
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
function forSubscriber(fn) {
|
|
665
|
+
const context = new WeakMap();
|
|
593
666
|
return (value, local) => {
|
|
594
667
|
if (!local)
|
|
595
668
|
return value;
|
|
596
|
-
if (!context.has(local))
|
|
597
|
-
|
|
669
|
+
if (!context.has(local)) {
|
|
670
|
+
const output = fn(local, context);
|
|
671
|
+
if (output) {
|
|
672
|
+
context.set(local, output);
|
|
673
|
+
return output;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
598
676
|
return context.get(local);
|
|
599
677
|
};
|
|
600
678
|
}
|
|
601
679
|
|
|
602
|
-
const Oops$
|
|
680
|
+
const Oops$8 = issues({
|
|
603
681
|
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
|
|
604
682
|
});
|
|
605
683
|
function act(task) {
|
|
@@ -607,7 +685,7 @@ function act(task) {
|
|
|
607
685
|
let pending = false;
|
|
608
686
|
const invoke = (...args) => {
|
|
609
687
|
if (pending)
|
|
610
|
-
return Promise.reject(Oops$
|
|
688
|
+
return Promise.reject(Oops$8.DuplicateAction(key));
|
|
611
689
|
pending = true;
|
|
612
690
|
this.update(key);
|
|
613
691
|
return new Promise(res => {
|
|
@@ -618,7 +696,6 @@ function act(task) {
|
|
|
618
696
|
});
|
|
619
697
|
};
|
|
620
698
|
this.state[key] = undefined;
|
|
621
|
-
setAlias(invoke, `run ${key}`);
|
|
622
699
|
defineProperty(invoke, "active", {
|
|
623
700
|
get: () => pending
|
|
624
701
|
});
|
|
@@ -629,104 +706,62 @@ function act(task) {
|
|
|
629
706
|
});
|
|
630
707
|
}
|
|
631
708
|
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
if (key in state)
|
|
657
|
-
return state[key];
|
|
658
|
-
let output;
|
|
659
|
-
try {
|
|
660
|
-
output = fn.call(subject, key, subject);
|
|
661
|
-
}
|
|
662
|
-
catch (err) {
|
|
663
|
-
throw error = err;
|
|
664
|
-
}
|
|
665
|
-
if (output instanceof Promise) {
|
|
666
|
-
const issue = Oops$9.ValueNotReady(subject, key);
|
|
667
|
-
output
|
|
668
|
-
.catch(err => error = err)
|
|
669
|
-
.then(out => state[key] = out)
|
|
670
|
-
.finally(() => waiting = undefined);
|
|
671
|
-
throw waiting = Object.assign(output, {
|
|
672
|
-
message: issue.message,
|
|
673
|
-
stack: issue.stack
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
else {
|
|
677
|
-
return state[key] = output;
|
|
678
|
-
}
|
|
679
|
-
};
|
|
709
|
+
class Managed extends Array {
|
|
710
|
+
constructor(onUpdate) {
|
|
711
|
+
super();
|
|
712
|
+
this.lastUpdate = [0, 0];
|
|
713
|
+
this.update = (from, to) => {
|
|
714
|
+
this.lastUpdate = [from, to];
|
|
715
|
+
onUpdate();
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
push(...items) {
|
|
719
|
+
const length = this.length;
|
|
720
|
+
const end = super.push(...items);
|
|
721
|
+
this.update(length, end);
|
|
722
|
+
return end;
|
|
723
|
+
}
|
|
724
|
+
unshift(...items) {
|
|
725
|
+
const end = super.push(...items);
|
|
726
|
+
this.update(0, end);
|
|
727
|
+
return end;
|
|
728
|
+
}
|
|
729
|
+
splice(start, deleteCount, ...rest) {
|
|
730
|
+
this.update(start, deleteCount !== rest.length ? Infinity : deleteCount);
|
|
731
|
+
return super.splice(start, deleteCount, ...rest);
|
|
732
|
+
}
|
|
680
733
|
}
|
|
681
|
-
function
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
734
|
+
function array() {
|
|
735
|
+
return apply(function array(key) {
|
|
736
|
+
const array = new Managed(() => this.update(key));
|
|
737
|
+
const access = forSubscriber(context => {
|
|
738
|
+
const local = Object.create(array);
|
|
739
|
+
const update = context.onUpdate(key, this);
|
|
740
|
+
let rangeA = 0;
|
|
741
|
+
let rangeB = 0;
|
|
742
|
+
function onUpdate() {
|
|
743
|
+
const [lastA, lastB] = array.lastUpdate;
|
|
744
|
+
if (rangeA <= lastB && rangeB >= lastA)
|
|
745
|
+
return update;
|
|
746
|
+
}
|
|
747
|
+
function listen(eventA, eventB) {
|
|
748
|
+
if (context.active)
|
|
749
|
+
return;
|
|
750
|
+
context.watch[key] = onUpdate;
|
|
751
|
+
rangeA = Math.min(rangeA, eventA);
|
|
752
|
+
rangeB = Math.max(rangeB, eventB);
|
|
753
|
+
}
|
|
754
|
+
local[Symbol.iterator] = () => {
|
|
755
|
+
listen(0, Infinity);
|
|
756
|
+
return array[Symbol.iterator]();
|
|
757
|
+
};
|
|
758
|
+
return local;
|
|
692
759
|
});
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
stack: error.stack
|
|
699
|
-
});
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
const Oops$8 = issues({
|
|
703
|
-
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
704
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
705
|
-
});
|
|
706
|
-
function from(source, setter, arg) {
|
|
707
|
-
return apply(function from(key) {
|
|
708
|
-
const { subject } = this;
|
|
709
|
-
let getSource;
|
|
710
|
-
let getter;
|
|
711
|
-
if (arg === true || setter === true)
|
|
712
|
-
getter = pendingValue;
|
|
713
|
-
if (typeof setter == "boolean")
|
|
714
|
-
setter = undefined;
|
|
715
|
-
// Easy mistake, using a peer, will always be unresolved.
|
|
716
|
-
if (typeof source == "symbol")
|
|
717
|
-
throw Oops$8.PeerNotAllowed(subject, key);
|
|
718
|
-
// replace source controller in-case it is different
|
|
719
|
-
if (typeof source == "object")
|
|
720
|
-
getSource = () => control(source);
|
|
721
|
-
// specifically an arrow function (getter factory)
|
|
722
|
-
else if (!source.prototype) {
|
|
723
|
-
setter = source.call(subject, key);
|
|
724
|
-
getSource = () => this;
|
|
725
|
-
}
|
|
726
|
-
// Regular function is too ambiguous so not allowed.
|
|
727
|
-
else
|
|
728
|
-
throw Oops$8.BadComputedSource(subject, key, source);
|
|
729
|
-
return prepare(this, key, getSource, setter, getter);
|
|
760
|
+
return {
|
|
761
|
+
get: access,
|
|
762
|
+
set: false,
|
|
763
|
+
value: array
|
|
764
|
+
};
|
|
730
765
|
});
|
|
731
766
|
}
|
|
732
767
|
|
|
@@ -755,32 +790,21 @@ function createRef(key, cb) {
|
|
|
755
790
|
const Oops$7 = issues({
|
|
756
791
|
NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
|
|
757
792
|
BadFactory: () => `Set instruction can only accept a factory or undefined.`,
|
|
793
|
+
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
758
794
|
FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
759
795
|
});
|
|
760
796
|
function set(factory, argument) {
|
|
761
797
|
return apply(function set(key) {
|
|
762
798
|
let set;
|
|
763
799
|
let get;
|
|
800
|
+
let suspense;
|
|
764
801
|
const required = argument === true || argument === undefined;
|
|
765
802
|
if (factory === undefined)
|
|
766
|
-
|
|
767
|
-
else if (typeof factory
|
|
803
|
+
suspense = true;
|
|
804
|
+
else if (typeof factory === "function")
|
|
805
|
+
get = pendingFactory(this, key, factory, required);
|
|
806
|
+
else
|
|
768
807
|
throw Oops$7.BadFactory();
|
|
769
|
-
else {
|
|
770
|
-
get = pendingFactory(this, key, factory);
|
|
771
|
-
if (required)
|
|
772
|
-
try {
|
|
773
|
-
get();
|
|
774
|
-
}
|
|
775
|
-
catch (err) {
|
|
776
|
-
if (err instanceof Promise)
|
|
777
|
-
;
|
|
778
|
-
else {
|
|
779
|
-
Oops$7.FactoryFailed(this.subject, key).warn();
|
|
780
|
-
throw err;
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
808
|
if (typeof argument == "function")
|
|
785
809
|
set = createValueEffect(argument);
|
|
786
810
|
else
|
|
@@ -788,8 +812,63 @@ function set(factory, argument) {
|
|
|
788
812
|
if (value === undefined && required)
|
|
789
813
|
throw Oops$7.NonOptional(this.subject, key);
|
|
790
814
|
};
|
|
791
|
-
return {
|
|
815
|
+
return {
|
|
816
|
+
set,
|
|
817
|
+
get,
|
|
818
|
+
suspense
|
|
819
|
+
};
|
|
792
820
|
});
|
|
821
|
+
}
|
|
822
|
+
function pendingFactory(parent, key, fn, required) {
|
|
823
|
+
const { subject, state } = parent;
|
|
824
|
+
let pending;
|
|
825
|
+
let error;
|
|
826
|
+
const init = () => {
|
|
827
|
+
const output = suspenseBoundary(() => {
|
|
828
|
+
return fn.call(subject, key, subject);
|
|
829
|
+
});
|
|
830
|
+
if (output instanceof Promise) {
|
|
831
|
+
pending = output
|
|
832
|
+
.catch(err => error = err)
|
|
833
|
+
.then(val => state[key] = val)
|
|
834
|
+
.finally(() => {
|
|
835
|
+
pending = undefined;
|
|
836
|
+
parent.update(key);
|
|
837
|
+
});
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
return state[key] = output;
|
|
841
|
+
};
|
|
842
|
+
const suspend = () => {
|
|
843
|
+
if (required === false)
|
|
844
|
+
return undefined;
|
|
845
|
+
const issue = Oops$7.ValueNotReady(subject, key);
|
|
846
|
+
Object.assign(pending, {
|
|
847
|
+
message: issue.message,
|
|
848
|
+
stack: issue.stack
|
|
849
|
+
});
|
|
850
|
+
throw pending;
|
|
851
|
+
};
|
|
852
|
+
if (required)
|
|
853
|
+
try {
|
|
854
|
+
init();
|
|
855
|
+
}
|
|
856
|
+
catch (err) {
|
|
857
|
+
Oops$7.FactoryFailed(subject, key).warn();
|
|
858
|
+
throw err;
|
|
859
|
+
}
|
|
860
|
+
return () => {
|
|
861
|
+
if (pending)
|
|
862
|
+
return suspend();
|
|
863
|
+
if (error)
|
|
864
|
+
throw error;
|
|
865
|
+
if (key in state)
|
|
866
|
+
return state[key];
|
|
867
|
+
let output = init();
|
|
868
|
+
return pending
|
|
869
|
+
? suspend()
|
|
870
|
+
: output;
|
|
871
|
+
};
|
|
793
872
|
}
|
|
794
873
|
|
|
795
874
|
const Parent = new WeakMap();
|
|
@@ -932,24 +1011,26 @@ const ContextWasUsed = new WeakMap();
|
|
|
932
1011
|
function tap(type, argument) {
|
|
933
1012
|
return apply(function tap(key) {
|
|
934
1013
|
if ("set" in type)
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1014
|
+
return {
|
|
1015
|
+
recursive: true,
|
|
1016
|
+
value: type.get()
|
|
1017
|
+
};
|
|
1018
|
+
const { subject } = this;
|
|
1019
|
+
if ("set" in subject.constructor)
|
|
1020
|
+
throw Oops$3.CantAttachGlobal(subject, type.name);
|
|
1021
|
+
getPending(subject).push(context => {
|
|
1022
|
+
let instance = context.get(type);
|
|
1023
|
+
if (typeof argument == "function") {
|
|
1024
|
+
if (argument(instance) === false)
|
|
1025
|
+
instance = undefined;
|
|
1026
|
+
}
|
|
1027
|
+
else if (!instance && argument)
|
|
1028
|
+
throw Oops$3.AmbientRequired(type.name, subject, key);
|
|
1029
|
+
this.update(key, instance);
|
|
1030
|
+
});
|
|
951
1031
|
return {
|
|
952
|
-
recursive: true
|
|
1032
|
+
recursive: true,
|
|
1033
|
+
suspense: true
|
|
953
1034
|
};
|
|
954
1035
|
});
|
|
955
1036
|
}
|
|
@@ -1247,7 +1328,7 @@ class Global extends MVC {
|
|
|
1247
1328
|
static set(updates) {
|
|
1248
1329
|
const instance = Active.get(this) || this.create();
|
|
1249
1330
|
instance.import(updates);
|
|
1250
|
-
return instance.update();
|
|
1331
|
+
return instance.update(false);
|
|
1251
1332
|
}
|
|
1252
1333
|
static get(arg) {
|
|
1253
1334
|
const instance = Active.get(this);
|
|
@@ -1269,5 +1350,5 @@ class Global extends MVC {
|
|
|
1269
1350
|
}
|
|
1270
1351
|
}
|
|
1271
1352
|
|
|
1272
|
-
export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, WHY, act, apply, MVC as default, from, parent, ref, set, tap, use$1 as use, useFrom, useInContext, useModel, useTap };
|
|
1353
|
+
export { CONTROL, Consumer, Global, LOCAL, MVC as Model, Provider, STATE, WHY, act, apply, array, MVC as default, from, parent, ref, set, tap, use$1 as use, useFrom, useInContext, useModel, useTap };
|
|
1273
1354
|
//# sourceMappingURL=index.esm.js.map
|