@expressive/mvc 1.0.0-beta.12 → 1.0.0-beta.17
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.js +521 -433
- package/package.json +2 -2
- package/types/index.d.ts +1 -0
- package/types/instructions.d.ts +31 -15
- package/types/model.d.ts +141 -65
- package/types/selector.ts +15 -0
- package/types/types.d.ts +1 -0
- package/types/dispatch.d.ts +0 -52
package/lib/index.js
CHANGED
|
@@ -44,13 +44,11 @@ function defineLazy(object, property, init) {
|
|
|
44
44
|
function setAlias(func, displayName) {
|
|
45
45
|
assign(func, { displayName });
|
|
46
46
|
}
|
|
47
|
-
function entriesIn(object) {
|
|
48
|
-
return entries(getOwnPropertyDescriptors(object));
|
|
49
|
-
}
|
|
50
47
|
function createEffect(callback) {
|
|
51
48
|
let unSet;
|
|
52
49
|
return function (value) {
|
|
53
|
-
typeof unSet == "function"
|
|
50
|
+
if (typeof unSet == "function")
|
|
51
|
+
unSet();
|
|
54
52
|
unSet = callback.call(this, value);
|
|
55
53
|
if (unSet instanceof Promise)
|
|
56
54
|
unSet = undefined;
|
|
@@ -58,6 +56,28 @@ function createEffect(callback) {
|
|
|
58
56
|
throw Oops$8.BadEffectCallback();
|
|
59
57
|
};
|
|
60
58
|
}
|
|
59
|
+
function createValueEffect(callback) {
|
|
60
|
+
let unSet;
|
|
61
|
+
return function (value) {
|
|
62
|
+
if (typeof unSet == "function")
|
|
63
|
+
unSet(value);
|
|
64
|
+
const out = callback.call(this, value);
|
|
65
|
+
if (typeof out == "boolean")
|
|
66
|
+
return out;
|
|
67
|
+
if (!out || out instanceof Promise)
|
|
68
|
+
return;
|
|
69
|
+
if (typeof out == "function")
|
|
70
|
+
unSet = out;
|
|
71
|
+
else
|
|
72
|
+
throw Oops$8.BadEffectCallback();
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
function select(source, select) {
|
|
76
|
+
const proxy = {};
|
|
77
|
+
for (const k in source)
|
|
78
|
+
proxy[k] = k;
|
|
79
|
+
return select(proxy);
|
|
80
|
+
}
|
|
61
81
|
function selectRecursive(using, keys) {
|
|
62
82
|
const found = new Set();
|
|
63
83
|
const spy = {};
|
|
@@ -72,6 +92,187 @@ function selectRecursive(using, keys) {
|
|
|
72
92
|
return Array.from(found);
|
|
73
93
|
}
|
|
74
94
|
|
|
95
|
+
const Lifecycle = {
|
|
96
|
+
WILL_RENDER: "willRender",
|
|
97
|
+
WILL_UPDATE: "willUpdate",
|
|
98
|
+
WILL_MOUNT: "willMount",
|
|
99
|
+
WILL_UNMOUNT: "willUnmount",
|
|
100
|
+
DID_MOUNT: "didMount"
|
|
101
|
+
};
|
|
102
|
+
const lifecycleEvents = [
|
|
103
|
+
"didCreate",
|
|
104
|
+
"willDestroy",
|
|
105
|
+
...values(Lifecycle)
|
|
106
|
+
];
|
|
107
|
+
function lifecycle(prefix) {
|
|
108
|
+
const type = eventsFor(prefix);
|
|
109
|
+
return function useLifecycle(sub, tag) {
|
|
110
|
+
const emit = react.useMemo(() => {
|
|
111
|
+
const subject = sub.source;
|
|
112
|
+
const id = typeof tag == "function" ? tag(subject) : tag;
|
|
113
|
+
return (name) => {
|
|
114
|
+
for (const key of [name, type(name)])
|
|
115
|
+
subject.update(key, id);
|
|
116
|
+
};
|
|
117
|
+
}, [sub, tag]);
|
|
118
|
+
emit(Lifecycle.WILL_RENDER);
|
|
119
|
+
emit(sub.active
|
|
120
|
+
? Lifecycle.WILL_UPDATE
|
|
121
|
+
: Lifecycle.WILL_MOUNT);
|
|
122
|
+
react.useLayoutEffect(() => {
|
|
123
|
+
sub.commit();
|
|
124
|
+
emit(Lifecycle.DID_MOUNT);
|
|
125
|
+
return () => {
|
|
126
|
+
emit(Lifecycle.WILL_UNMOUNT);
|
|
127
|
+
sub.release();
|
|
128
|
+
};
|
|
129
|
+
}, [sub]);
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function eventsFor(prefix) {
|
|
133
|
+
const map = new Map();
|
|
134
|
+
for (const name of values(Lifecycle)) {
|
|
135
|
+
const alias = prefix + name[0].toUpperCase() + name.slice(1);
|
|
136
|
+
lifecycleEvents.push(alias);
|
|
137
|
+
map.set(name, alias);
|
|
138
|
+
}
|
|
139
|
+
return (e) => map.get(e);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const CONTROL = Symbol("control");
|
|
143
|
+
const CREATE = Symbol("start");
|
|
144
|
+
const LOCAL = Symbol("local");
|
|
145
|
+
const STATE = Symbol("state");
|
|
146
|
+
const Pending = new Map();
|
|
147
|
+
function manage(src) {
|
|
148
|
+
return src[CONTROL];
|
|
149
|
+
}
|
|
150
|
+
function does(instruction, label) {
|
|
151
|
+
const placeholder = Symbol(`${label} instruction`);
|
|
152
|
+
Pending.set(placeholder, instruction);
|
|
153
|
+
return placeholder;
|
|
154
|
+
}
|
|
155
|
+
class Controller {
|
|
156
|
+
constructor(subject) {
|
|
157
|
+
this.subject = subject;
|
|
158
|
+
this.state = {};
|
|
159
|
+
this.frame = new Set();
|
|
160
|
+
this.handles = new Set();
|
|
161
|
+
this.waiting = [];
|
|
162
|
+
}
|
|
163
|
+
static setup(onto) {
|
|
164
|
+
const create = onto[CREATE];
|
|
165
|
+
const control = new this(onto);
|
|
166
|
+
const after = create && create.call(onto, control);
|
|
167
|
+
defineLazy(onto, CONTROL, () => {
|
|
168
|
+
onto[STATE] = control.state;
|
|
169
|
+
control.start();
|
|
170
|
+
if (after)
|
|
171
|
+
after();
|
|
172
|
+
if (onto.didCreate)
|
|
173
|
+
onto.didCreate();
|
|
174
|
+
return control;
|
|
175
|
+
});
|
|
176
|
+
return control;
|
|
177
|
+
}
|
|
178
|
+
get pending() {
|
|
179
|
+
return this.frame.size > 0;
|
|
180
|
+
}
|
|
181
|
+
start() {
|
|
182
|
+
const { subject } = this;
|
|
183
|
+
for (const key in subject) {
|
|
184
|
+
const desc = getOwnPropertyDescriptor(subject, key);
|
|
185
|
+
if (desc && "value" in desc) {
|
|
186
|
+
const { value } = desc;
|
|
187
|
+
const instruction = Pending.get(value);
|
|
188
|
+
if (instruction) {
|
|
189
|
+
Pending.delete(value);
|
|
190
|
+
delete subject[key];
|
|
191
|
+
instruction.call(this, key, this);
|
|
192
|
+
}
|
|
193
|
+
else if (typeof value !== "function" || /^[A-Z]/.test(key))
|
|
194
|
+
this.manage(key, value);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
this.emit();
|
|
198
|
+
return this;
|
|
199
|
+
}
|
|
200
|
+
select(using) {
|
|
201
|
+
const keys = getOwnPropertyNames(this.state);
|
|
202
|
+
return using
|
|
203
|
+
? selectRecursive(using, keys.concat(lifecycleEvents))
|
|
204
|
+
: keys;
|
|
205
|
+
}
|
|
206
|
+
manage(key, initial, effect) {
|
|
207
|
+
const { state, subject } = this;
|
|
208
|
+
state[key] = initial;
|
|
209
|
+
defineProperty(subject, key, {
|
|
210
|
+
enumerable: true,
|
|
211
|
+
configurable: true,
|
|
212
|
+
get: () => state[key],
|
|
213
|
+
set: this.setter(key, effect)
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
setter(key, handler) {
|
|
217
|
+
const { state, subject } = this;
|
|
218
|
+
return (value) => {
|
|
219
|
+
if (state[key] == value)
|
|
220
|
+
return;
|
|
221
|
+
if (handler)
|
|
222
|
+
switch (handler.call(subject, value)) {
|
|
223
|
+
case true:
|
|
224
|
+
this.update(key);
|
|
225
|
+
case false:
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
this.update(key, value);
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
addListener(batch) {
|
|
232
|
+
this.handles.add(batch);
|
|
233
|
+
return () => {
|
|
234
|
+
this.handles.delete(batch);
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
include(to) {
|
|
238
|
+
if (capture(this, to))
|
|
239
|
+
return;
|
|
240
|
+
else
|
|
241
|
+
this.waiting.push(to);
|
|
242
|
+
}
|
|
243
|
+
update(key, value) {
|
|
244
|
+
if (1 in arguments)
|
|
245
|
+
this.state[key] = value;
|
|
246
|
+
if (this.frame.has(key))
|
|
247
|
+
return;
|
|
248
|
+
if (!this.frame.size)
|
|
249
|
+
setTimeout(() => this.emit(), 0);
|
|
250
|
+
this.frame.add(key);
|
|
251
|
+
for (const subscription of this.handles)
|
|
252
|
+
if (key in subscription)
|
|
253
|
+
this.include(subscription[key]);
|
|
254
|
+
}
|
|
255
|
+
emit() {
|
|
256
|
+
flush(this);
|
|
257
|
+
const keys = Array.from(this.frame);
|
|
258
|
+
const handle = new Set(this.waiting.splice(0));
|
|
259
|
+
this.frame.clear();
|
|
260
|
+
handle.forEach(callback => {
|
|
261
|
+
try {
|
|
262
|
+
callback(keys);
|
|
263
|
+
}
|
|
264
|
+
catch (e) { }
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
function keys(from, using) {
|
|
269
|
+
if (typeof using == "string")
|
|
270
|
+
return [using];
|
|
271
|
+
if (typeof using == "object")
|
|
272
|
+
return Array.from(using);
|
|
273
|
+
return from.select(using);
|
|
274
|
+
}
|
|
275
|
+
|
|
75
276
|
class Subscriber {
|
|
76
277
|
constructor(parent, onUpdate) {
|
|
77
278
|
this.onUpdate = onUpdate;
|
|
@@ -132,6 +333,15 @@ function getRegister(on) {
|
|
|
132
333
|
ComputedUsed.set(on, register = new Map());
|
|
133
334
|
return register;
|
|
134
335
|
}
|
|
336
|
+
function prepareGetters(on) {
|
|
337
|
+
const defined = getRegister(on);
|
|
338
|
+
for (let scan = on.subject; scan.constructor !== Object; scan = getPrototypeOf(scan))
|
|
339
|
+
for (const key of getOwnPropertyNames(scan)) {
|
|
340
|
+
const { get, set } = getOwnPropertyDescriptor(scan, key);
|
|
341
|
+
if (get && !defined.has(key))
|
|
342
|
+
prepare(on, key, get, set);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
135
345
|
function prepare(on, key, getter, setter) {
|
|
136
346
|
const { state, subject } = on;
|
|
137
347
|
const defined = getRegister(on);
|
|
@@ -194,6 +404,14 @@ function prepare(on, key, getter, setter) {
|
|
|
194
404
|
}
|
|
195
405
|
}
|
|
196
406
|
}
|
|
407
|
+
function revert(value) {
|
|
408
|
+
delete state[key];
|
|
409
|
+
defineProperty(subject, key, {
|
|
410
|
+
enumerable: true,
|
|
411
|
+
configurable: true,
|
|
412
|
+
value
|
|
413
|
+
});
|
|
414
|
+
}
|
|
197
415
|
setAlias(update, `try ${key}`);
|
|
198
416
|
setAlias(create, `new ${key}`);
|
|
199
417
|
setAlias(getter, `run ${key}`);
|
|
@@ -201,6 +419,7 @@ function prepare(on, key, getter, setter) {
|
|
|
201
419
|
for (const on of [state, subject])
|
|
202
420
|
defineProperty(on, key, {
|
|
203
421
|
get: create,
|
|
422
|
+
set: setter || revert,
|
|
204
423
|
configurable: true,
|
|
205
424
|
enumerable: true
|
|
206
425
|
});
|
|
@@ -216,16 +435,17 @@ function ensure(on, keys) {
|
|
|
216
435
|
}
|
|
217
436
|
function capture(on, request) {
|
|
218
437
|
const compute = ComputedInfo.get(request);
|
|
438
|
+
const callback = request;
|
|
219
439
|
if (!compute)
|
|
220
440
|
return;
|
|
221
441
|
let pending = ComputedKeys.get(on);
|
|
222
442
|
if (!pending)
|
|
223
443
|
ComputedKeys.set(on, pending = []);
|
|
224
444
|
if (compute.parent !== on)
|
|
225
|
-
|
|
445
|
+
callback();
|
|
226
446
|
else {
|
|
227
|
-
const
|
|
228
|
-
pending.splice(
|
|
447
|
+
const queue = pending.findIndex(peer => compute.priority > ComputedInfo.get(peer).priority);
|
|
448
|
+
pending.splice(queue + 1, 0, callback);
|
|
229
449
|
}
|
|
230
450
|
return true;
|
|
231
451
|
}
|
|
@@ -244,36 +464,22 @@ function flush(on) {
|
|
|
244
464
|
}
|
|
245
465
|
|
|
246
466
|
const Oops$6 = issues({
|
|
247
|
-
DuplicateAction: (key) => `Invoked action ${key} but one is already active
|
|
467
|
+
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
|
|
468
|
+
SourceNotSupported: () => `Computed from-instruction does not support source other than 'this'.`
|
|
248
469
|
});
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
const placeholder = Symbol(`${name} instruction`);
|
|
261
|
-
function apply(key) {
|
|
262
|
-
let output = instruction.call(this, key);
|
|
263
|
-
if (typeof output == "function") {
|
|
264
|
-
const getter = output;
|
|
265
|
-
output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
|
|
266
|
-
return getter(this[LOCAL]);
|
|
267
|
-
} });
|
|
268
|
-
}
|
|
269
|
-
if (output)
|
|
270
|
-
defineProperty(this.subject, key, output);
|
|
271
|
-
}
|
|
272
|
-
Pending.set(placeholder, apply);
|
|
273
|
-
return placeholder;
|
|
274
|
-
}
|
|
470
|
+
const set = (fn, name) => does(function set(key) {
|
|
471
|
+
let output = fn.call(this, key, this);
|
|
472
|
+
if (typeof output == "function") {
|
|
473
|
+
const getter = output;
|
|
474
|
+
output = Object.assign(Object.assign({}, getOwnPropertyDescriptor(this.subject, key)), { get() {
|
|
475
|
+
return getter(this[LOCAL]);
|
|
476
|
+
} });
|
|
477
|
+
}
|
|
478
|
+
if (output)
|
|
479
|
+
defineProperty(this.subject, key, output);
|
|
480
|
+
}, name || fn.name || "pending");
|
|
275
481
|
const ref = (cb) => set(function ref(key) {
|
|
276
|
-
const refObjectFunction = this.
|
|
482
|
+
const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
|
|
277
483
|
defineProperty(refObjectFunction, "current", {
|
|
278
484
|
set: refObjectFunction,
|
|
279
485
|
get: () => this.state[key]
|
|
@@ -282,8 +488,8 @@ const ref = (cb) => set(function ref(key) {
|
|
|
282
488
|
value: refObjectFunction
|
|
283
489
|
};
|
|
284
490
|
});
|
|
285
|
-
const on = (
|
|
286
|
-
this.manage(key,
|
|
491
|
+
const on = (initial, cb) => set(function on(key) {
|
|
492
|
+
this.manage(key, initial, cb && createValueEffect(cb));
|
|
287
493
|
});
|
|
288
494
|
const memo = (factory, defer) => set(function memo(key) {
|
|
289
495
|
const source = this.subject;
|
|
@@ -314,279 +520,83 @@ const act = (task) => set(function act(key) {
|
|
|
314
520
|
this.update(key);
|
|
315
521
|
});
|
|
316
522
|
};
|
|
317
|
-
setAlias(invoke, `run ${key}`);
|
|
318
|
-
defineProperty(invoke, "active", {
|
|
319
|
-
get: () => pending
|
|
320
|
-
});
|
|
321
|
-
return {
|
|
322
|
-
value: invoke,
|
|
323
|
-
writable: false
|
|
324
|
-
};
|
|
325
|
-
});
|
|
326
|
-
const from = (getter) => set(function from(key) {
|
|
327
|
-
prepare(this, key, getter);
|
|
328
|
-
});
|
|
329
|
-
|
|
330
|
-
const Lifecycle = {
|
|
331
|
-
WILL_RENDER: "willRender",
|
|
332
|
-
WILL_UPDATE: "willUpdate",
|
|
333
|
-
WILL_MOUNT: "willMount",
|
|
334
|
-
WILL_UNMOUNT: "willUnmount",
|
|
335
|
-
DID_MOUNT: "didMount"
|
|
336
|
-
};
|
|
337
|
-
const lifecycleEvents = [
|
|
338
|
-
"didCreate",
|
|
339
|
-
"willDestroy",
|
|
340
|
-
...values(Lifecycle)
|
|
341
|
-
];
|
|
342
|
-
function lifecycle(prefix) {
|
|
343
|
-
const type = eventsFor(prefix);
|
|
344
|
-
return function useLifecycle(sub, tag) {
|
|
345
|
-
const emit = react.useMemo(() => {
|
|
346
|
-
const { parent } = sub;
|
|
347
|
-
const { subject } = parent;
|
|
348
|
-
const id = typeof tag == "function" ? tag(subject) : tag;
|
|
349
|
-
return (name) => {
|
|
350
|
-
for (const key of [name, type(name)]) {
|
|
351
|
-
const handler = subject[key];
|
|
352
|
-
if (handler)
|
|
353
|
-
handler.call(subject, id);
|
|
354
|
-
parent.update(key);
|
|
355
|
-
}
|
|
356
|
-
};
|
|
357
|
-
}, [sub, tag]);
|
|
358
|
-
emit(Lifecycle.WILL_RENDER);
|
|
359
|
-
emit(sub.active
|
|
360
|
-
? Lifecycle.WILL_UPDATE
|
|
361
|
-
: Lifecycle.WILL_MOUNT);
|
|
362
|
-
react.useLayoutEffect(() => {
|
|
363
|
-
sub.commit();
|
|
364
|
-
emit(Lifecycle.DID_MOUNT);
|
|
365
|
-
return () => {
|
|
366
|
-
emit(Lifecycle.WILL_UNMOUNT);
|
|
367
|
-
sub.release();
|
|
368
|
-
};
|
|
369
|
-
}, [sub]);
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
function eventsFor(prefix) {
|
|
373
|
-
const map = new Map();
|
|
374
|
-
for (const name of values(Lifecycle)) {
|
|
375
|
-
const alias = prefix + name[0].toUpperCase() + name.slice(1);
|
|
376
|
-
lifecycleEvents.push(alias);
|
|
377
|
-
map.set(name, alias);
|
|
378
|
-
}
|
|
379
|
-
return (e) => map.get(e);
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
const CONTROL = Symbol("control");
|
|
383
|
-
const LOCAL = Symbol("local");
|
|
384
|
-
const STATE = Symbol("state");
|
|
385
|
-
function manage(src) {
|
|
386
|
-
return src[CONTROL];
|
|
387
|
-
}
|
|
388
|
-
class Controller {
|
|
389
|
-
constructor(subject) {
|
|
390
|
-
this.subject = subject;
|
|
391
|
-
this.state = {};
|
|
392
|
-
this.frame = new Set();
|
|
393
|
-
this.handles = new Set();
|
|
394
|
-
this.waiting = [];
|
|
395
|
-
}
|
|
396
|
-
static init(onto, after) {
|
|
397
|
-
const control = new this(onto);
|
|
398
|
-
defer(control, "on");
|
|
399
|
-
defer(control, "effect");
|
|
400
|
-
defineLazy(onto, CONTROL, () => {
|
|
401
|
-
delete onto.on;
|
|
402
|
-
delete onto.effect;
|
|
403
|
-
onto[STATE] = control.state;
|
|
404
|
-
control.start();
|
|
405
|
-
after && after();
|
|
406
|
-
return control;
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
get pending() {
|
|
410
|
-
return this.frame.size > 0;
|
|
411
|
-
}
|
|
412
|
-
start() {
|
|
413
|
-
entriesIn(this.subject).forEach(([key, desc]) => {
|
|
414
|
-
if (desc && desc.enumerable && "value" in desc) {
|
|
415
|
-
const { value } = desc;
|
|
416
|
-
if (apply(this, key, value))
|
|
417
|
-
return;
|
|
418
|
-
if (typeof value !== "function" || /^[A-Z]/.test(key))
|
|
419
|
-
this.manage(key, value);
|
|
420
|
-
}
|
|
421
|
-
});
|
|
422
|
-
this.emit();
|
|
423
|
-
return this;
|
|
424
|
-
}
|
|
425
|
-
select(using) {
|
|
426
|
-
const keys = getOwnPropertyNames(this.state);
|
|
427
|
-
return using
|
|
428
|
-
? selectRecursive(using, keys.concat(lifecycleEvents))
|
|
429
|
-
: keys;
|
|
430
|
-
}
|
|
431
|
-
manage(key, initial, effect) {
|
|
432
|
-
const { state, subject } = this;
|
|
433
|
-
state[key] = initial;
|
|
434
|
-
defineProperty(subject, key, {
|
|
435
|
-
enumerable: true,
|
|
436
|
-
configurable: true,
|
|
437
|
-
get: () => state[key],
|
|
438
|
-
set: this.sets(key, effect)
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
sets(key, handler) {
|
|
442
|
-
const { state, subject } = this;
|
|
443
|
-
return (value) => {
|
|
444
|
-
if (state[key] == value)
|
|
445
|
-
return;
|
|
446
|
-
if (handler)
|
|
447
|
-
switch (handler.call(subject, value)) {
|
|
448
|
-
case true:
|
|
449
|
-
this.update(key);
|
|
450
|
-
case false:
|
|
451
|
-
return;
|
|
452
|
-
}
|
|
453
|
-
this.update(key, value);
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
watch(subset, handler, squash, once) {
|
|
457
|
-
const set = keys(this, subset);
|
|
458
|
-
const batch = {};
|
|
459
|
-
const remove = this.addListener(batch);
|
|
460
|
-
const callback = squash
|
|
461
|
-
? handler.bind(this.subject)
|
|
462
|
-
: (frame) => {
|
|
463
|
-
for (const key of frame)
|
|
464
|
-
if (set.includes(key))
|
|
465
|
-
handler.call(this.subject, this.state[key], key);
|
|
466
|
-
};
|
|
467
|
-
const handle = once
|
|
468
|
-
? (k) => { remove(); callback(k); }
|
|
469
|
-
: callback;
|
|
470
|
-
for (const key of set)
|
|
471
|
-
batch[key] = handle;
|
|
472
|
-
ensure(this, set);
|
|
473
|
-
return remove;
|
|
474
|
-
}
|
|
475
|
-
addListener(batch) {
|
|
476
|
-
this.handles.add(batch);
|
|
477
|
-
return () => {
|
|
478
|
-
this.handles.delete(batch);
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
include(to) {
|
|
482
|
-
if (capture(this, to))
|
|
483
|
-
return;
|
|
484
|
-
else
|
|
485
|
-
this.waiting.push(to);
|
|
486
|
-
}
|
|
487
|
-
update(key, value) {
|
|
488
|
-
if (1 in arguments)
|
|
489
|
-
this.state[key] = value;
|
|
490
|
-
if (this.frame.has(key))
|
|
491
|
-
return;
|
|
492
|
-
if (!this.frame.size)
|
|
493
|
-
setTimeout(() => this.emit(), 0);
|
|
494
|
-
this.frame.add(key);
|
|
495
|
-
for (const subscription of this.handles)
|
|
496
|
-
if (key in subscription)
|
|
497
|
-
this.include(subscription[key]);
|
|
498
|
-
}
|
|
499
|
-
emit() {
|
|
500
|
-
flush(this);
|
|
501
|
-
const keys = Array.from(this.frame);
|
|
502
|
-
const handle = new Set(this.waiting.splice(0));
|
|
503
|
-
this.frame.clear();
|
|
504
|
-
handle.forEach(cb => {
|
|
505
|
-
try {
|
|
506
|
-
cb(keys);
|
|
507
|
-
}
|
|
508
|
-
catch (e) { }
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
function keys(from, using) {
|
|
513
|
-
if (typeof using == "string")
|
|
514
|
-
return [using];
|
|
515
|
-
if (typeof using == "object")
|
|
516
|
-
return Array.from(using);
|
|
517
|
-
return from.select(using);
|
|
518
|
-
}
|
|
519
|
-
function defer(on, method) {
|
|
520
|
-
const { subject, waiting } = on;
|
|
521
|
-
const real = subject[method];
|
|
522
|
-
subject[method] = (...args) => {
|
|
523
|
-
let done;
|
|
524
|
-
waiting.push(() => {
|
|
525
|
-
done = real.apply(subject, args);
|
|
526
|
-
});
|
|
527
|
-
return () => done();
|
|
528
|
-
};
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
const Oops$5 = issues({
|
|
532
|
-
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
533
|
-
AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
|
|
523
|
+
setAlias(invoke, `run ${key}`);
|
|
524
|
+
defineProperty(invoke, "active", {
|
|
525
|
+
get: () => pending
|
|
526
|
+
});
|
|
527
|
+
return {
|
|
528
|
+
value: invoke,
|
|
529
|
+
writable: false
|
|
530
|
+
};
|
|
534
531
|
});
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
getPending(to).push(context => {
|
|
545
|
-
instance = context.get(type);
|
|
546
|
-
if (typeof argument == "function") {
|
|
547
|
-
if (argument(instance) === false)
|
|
548
|
-
instance = undefined;
|
|
532
|
+
function from(source, fn) {
|
|
533
|
+
return set(function from(key) {
|
|
534
|
+
let getter;
|
|
535
|
+
if (typeof source == "function")
|
|
536
|
+
getter = source.call(this.subject, key);
|
|
537
|
+
else {
|
|
538
|
+
if (source !== this.subject)
|
|
539
|
+
throw Oops$6.SourceNotSupported();
|
|
540
|
+
getter = fn;
|
|
549
541
|
}
|
|
550
|
-
|
|
551
|
-
throw Oops$5.AmbientRequired(type.name, to, key);
|
|
542
|
+
prepare(this, key, getter);
|
|
552
543
|
});
|
|
553
|
-
return () => instance;
|
|
554
|
-
});
|
|
555
|
-
function usePeerContext(subject) {
|
|
556
|
-
if (ContextWasUsed.has(subject)) {
|
|
557
|
-
if (ContextWasUsed.get(subject))
|
|
558
|
-
useLookup();
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
const pending = PendingContext.get(subject);
|
|
562
|
-
if (pending) {
|
|
563
|
-
const local = useLookup();
|
|
564
|
-
for (const init of pending)
|
|
565
|
-
init(local);
|
|
566
|
-
PendingContext.delete(subject);
|
|
567
|
-
}
|
|
568
|
-
ContextWasUsed.set(subject, !!pending);
|
|
569
|
-
}
|
|
570
|
-
function getPending(subject) {
|
|
571
|
-
let pending = PendingContext.get(subject);
|
|
572
|
-
if (!pending)
|
|
573
|
-
PendingContext.set(subject, pending = []);
|
|
574
|
-
return pending;
|
|
575
544
|
}
|
|
576
545
|
|
|
577
|
-
const
|
|
546
|
+
const attach = (from, name) => set(function attach(key) {
|
|
547
|
+
const proxyCache = new WeakMap();
|
|
548
|
+
const getCurrent = from.call(this, key);
|
|
549
|
+
function subscribe(sub) {
|
|
550
|
+
let child;
|
|
551
|
+
function start() {
|
|
552
|
+
const instance = getCurrent();
|
|
553
|
+
if (instance) {
|
|
554
|
+
child = new Subscriber(instance, sub.onUpdate);
|
|
555
|
+
if (sub.active)
|
|
556
|
+
child.commit();
|
|
557
|
+
sub.dependant.add(child);
|
|
558
|
+
proxyCache.set(sub, child.proxy);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
function refresh() {
|
|
562
|
+
if (child) {
|
|
563
|
+
child.release();
|
|
564
|
+
sub.dependant.delete(child);
|
|
565
|
+
proxyCache.set(sub, undefined);
|
|
566
|
+
child = undefined;
|
|
567
|
+
}
|
|
568
|
+
start();
|
|
569
|
+
sub.onUpdate();
|
|
570
|
+
}
|
|
571
|
+
start();
|
|
572
|
+
sub.follow(key, refresh);
|
|
573
|
+
}
|
|
574
|
+
return (local) => {
|
|
575
|
+
if (!local)
|
|
576
|
+
return getCurrent();
|
|
577
|
+
if (!proxyCache.has(local))
|
|
578
|
+
subscribe(local);
|
|
579
|
+
return proxyCache.get(local);
|
|
580
|
+
};
|
|
581
|
+
}, name || from.name);
|
|
582
|
+
|
|
583
|
+
const Oops$5 = issues({
|
|
578
584
|
HasPropertyUndefined: (control, property) => `${control}.${property} is marked as required for this render.`
|
|
579
585
|
});
|
|
580
586
|
const useElementLifecycle = lifecycle("element");
|
|
581
|
-
const useComponentLifecycle = lifecycle("component");
|
|
582
587
|
function use$1(init) {
|
|
583
588
|
const [state, update] = react.useState(() => [
|
|
584
589
|
init(() => update(state.concat()))
|
|
585
590
|
]);
|
|
586
591
|
return state[0];
|
|
587
592
|
}
|
|
588
|
-
function useLazy(Type, args) {
|
|
589
|
-
const instance = react.useMemo(() =>
|
|
593
|
+
function useLazy(Type, args, callback) {
|
|
594
|
+
const instance = react.useMemo(() => {
|
|
595
|
+
const instance = Type.create(...args || []);
|
|
596
|
+
if (callback)
|
|
597
|
+
callback(instance);
|
|
598
|
+
return instance;
|
|
599
|
+
}, []);
|
|
590
600
|
react.useLayoutEffect(() => () => instance.destroy(), []);
|
|
591
601
|
return instance;
|
|
592
602
|
}
|
|
@@ -599,7 +609,7 @@ function useWatcher(target, focus, expected) {
|
|
|
599
609
|
defineProperty(sub, "proxy", {
|
|
600
610
|
get() {
|
|
601
611
|
if (src[key] === undefined && expected)
|
|
602
|
-
throw Oops$
|
|
612
|
+
throw Oops$5.HasPropertyUndefined(target, key);
|
|
603
613
|
return src[key];
|
|
604
614
|
}
|
|
605
615
|
});
|
|
@@ -616,17 +626,19 @@ function useSubscriber(target, tag) {
|
|
|
616
626
|
}
|
|
617
627
|
function useModel(Type, args, callback) {
|
|
618
628
|
const hook = use$1(refresh => {
|
|
619
|
-
const instance = new Type(...args);
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
629
|
+
const instance = new Type(...args || []);
|
|
630
|
+
const control = manage(instance);
|
|
631
|
+
const sub = new Subscriber(control, refresh);
|
|
632
|
+
const release = control.addListener({
|
|
633
|
+
[Lifecycle.WILL_UNMOUNT]() {
|
|
634
|
+
instance.destroy();
|
|
635
|
+
release();
|
|
636
|
+
}
|
|
623
637
|
});
|
|
624
638
|
if (callback)
|
|
625
639
|
callback(instance);
|
|
626
640
|
return sub;
|
|
627
641
|
});
|
|
628
|
-
usePeerContext(hook.parent.subject);
|
|
629
|
-
useComponentLifecycle(hook);
|
|
630
642
|
return hook.proxy;
|
|
631
643
|
}
|
|
632
644
|
|
|
@@ -670,10 +682,10 @@ class Lookup {
|
|
|
670
682
|
}
|
|
671
683
|
do {
|
|
672
684
|
defineProperty(this, this.key(T), {
|
|
673
|
-
value: I,
|
|
674
|
-
writable
|
|
685
|
+
value: I, writable
|
|
675
686
|
});
|
|
676
|
-
|
|
687
|
+
T = getPrototypeOf(T);
|
|
688
|
+
} while (T !== Model);
|
|
677
689
|
return I;
|
|
678
690
|
}
|
|
679
691
|
pop() {
|
|
@@ -685,7 +697,7 @@ class Lookup {
|
|
|
685
697
|
}
|
|
686
698
|
}
|
|
687
699
|
|
|
688
|
-
const Oops$
|
|
700
|
+
const Oops$4 = issues({
|
|
689
701
|
NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`,
|
|
690
702
|
NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`,
|
|
691
703
|
BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
@@ -695,7 +707,7 @@ const useLookup = () => react.useContext(LookupContext);
|
|
|
695
707
|
function useFromContext(Type, strict) {
|
|
696
708
|
const instance = useLookup().get(Type);
|
|
697
709
|
if (!instance && strict)
|
|
698
|
-
throw Oops$
|
|
710
|
+
throw Oops$4.NothingInContext(Type.name);
|
|
699
711
|
return instance;
|
|
700
712
|
}
|
|
701
713
|
function Consumer(props) {
|
|
@@ -706,13 +718,13 @@ function Consumer(props) {
|
|
|
706
718
|
if (typeof callback == "function")
|
|
707
719
|
callback(Control.get(!!has));
|
|
708
720
|
else
|
|
709
|
-
throw Oops$
|
|
721
|
+
throw Oops$4.BadConsumerProps();
|
|
710
722
|
return null;
|
|
711
723
|
}
|
|
712
724
|
function useNewContext(from, inject) {
|
|
713
725
|
return react.useMemo(() => {
|
|
714
726
|
if (!inject)
|
|
715
|
-
throw Oops$
|
|
727
|
+
throw Oops$4.NoProviderType();
|
|
716
728
|
const context = from.push(inject);
|
|
717
729
|
for (const instance of context.local)
|
|
718
730
|
for (const apply of getPending(instance))
|
|
@@ -755,50 +767,63 @@ function Provider(props) {
|
|
|
755
767
|
: render);
|
|
756
768
|
}
|
|
757
769
|
|
|
770
|
+
const Oops$3 = issues({
|
|
771
|
+
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
772
|
+
AmbientRequired: (requested, requester, key) => `Attempted to find an instance of ${requested} in context. It is required for [${requester}.${key}], but one could not be found.`
|
|
773
|
+
});
|
|
774
|
+
const PendingContext = new WeakMap();
|
|
775
|
+
const ContextWasUsed = new WeakMap();
|
|
776
|
+
const tap = (type, argument) => attach(function tap(key) {
|
|
777
|
+
if ("current" in type)
|
|
778
|
+
return () => type.current;
|
|
779
|
+
const to = this.subject;
|
|
780
|
+
if ("current" in to.constructor)
|
|
781
|
+
throw Oops$3.CantAttachGlobal(to, type.name);
|
|
782
|
+
let instance;
|
|
783
|
+
getPending(to).push(context => {
|
|
784
|
+
instance = context.get(type);
|
|
785
|
+
if (typeof argument == "function") {
|
|
786
|
+
if (argument(instance) === false)
|
|
787
|
+
instance = undefined;
|
|
788
|
+
}
|
|
789
|
+
else if (!instance && argument)
|
|
790
|
+
throw Oops$3.AmbientRequired(type.name, to, key);
|
|
791
|
+
});
|
|
792
|
+
return () => instance;
|
|
793
|
+
});
|
|
794
|
+
function usePeerContext(subject) {
|
|
795
|
+
if (ContextWasUsed.has(subject)) {
|
|
796
|
+
if (ContextWasUsed.get(subject))
|
|
797
|
+
useLookup();
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const pending = PendingContext.get(subject);
|
|
801
|
+
if (pending) {
|
|
802
|
+
const local = useLookup();
|
|
803
|
+
for (const init of pending)
|
|
804
|
+
init(local);
|
|
805
|
+
PendingContext.delete(subject);
|
|
806
|
+
}
|
|
807
|
+
ContextWasUsed.set(subject, !!pending);
|
|
808
|
+
}
|
|
809
|
+
function getPending(subject) {
|
|
810
|
+
let pending = PendingContext.get(subject);
|
|
811
|
+
if (!pending)
|
|
812
|
+
PendingContext.set(subject, pending = []);
|
|
813
|
+
return pending;
|
|
814
|
+
}
|
|
815
|
+
|
|
758
816
|
const Oops$2 = issues({
|
|
759
|
-
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates
|
|
817
|
+
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
818
|
+
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
760
819
|
});
|
|
761
|
-
class
|
|
762
|
-
constructor() {
|
|
820
|
+
class State {
|
|
821
|
+
constructor(computeGetters) {
|
|
822
|
+
const control = Controller.setup(this);
|
|
763
823
|
define(this, "get", this);
|
|
764
824
|
define(this, "set", this);
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
this.didCreate();
|
|
768
|
-
});
|
|
769
|
-
}
|
|
770
|
-
tap(path, expect) {
|
|
771
|
-
return useWatcher(this, path, expect);
|
|
772
|
-
}
|
|
773
|
-
tag(id) {
|
|
774
|
-
return useSubscriber(this, id);
|
|
775
|
-
}
|
|
776
|
-
on(select, callback, squash, once) {
|
|
777
|
-
return manage(this).watch(select, callback, squash, once);
|
|
778
|
-
}
|
|
779
|
-
once(select, callback, squash) {
|
|
780
|
-
if (callback)
|
|
781
|
-
return this.on(select, callback, squash, true);
|
|
782
|
-
else
|
|
783
|
-
return new Promise(resolve => {
|
|
784
|
-
this.on(select, resolve, true, true);
|
|
785
|
-
});
|
|
786
|
-
}
|
|
787
|
-
effect(callback, select) {
|
|
788
|
-
const control = manage(this);
|
|
789
|
-
let target = this;
|
|
790
|
-
const effect = createEffect(callback);
|
|
791
|
-
const invoke = () => effect.call(target, target);
|
|
792
|
-
if (select) {
|
|
793
|
-
invoke();
|
|
794
|
-
return this.on(select, invoke, true);
|
|
795
|
-
}
|
|
796
|
-
else {
|
|
797
|
-
const sub = new Subscriber(control, invoke);
|
|
798
|
-
target = sub.proxy;
|
|
799
|
-
invoke();
|
|
800
|
-
return sub.commit();
|
|
801
|
-
}
|
|
825
|
+
if (computeGetters !== false)
|
|
826
|
+
prepareGetters(control);
|
|
802
827
|
}
|
|
803
828
|
import(from, subset) {
|
|
804
829
|
for (const key of keys(manage(this), subset))
|
|
@@ -812,46 +837,66 @@ class Model {
|
|
|
812
837
|
output[key] = control.state[key];
|
|
813
838
|
return output;
|
|
814
839
|
}
|
|
815
|
-
update(arg) {
|
|
840
|
+
update(arg, tag) {
|
|
816
841
|
const control = manage(this);
|
|
842
|
+
if (typeof arg == "function")
|
|
843
|
+
arg = select(this, arg);
|
|
817
844
|
if (typeof arg == "boolean") {
|
|
818
845
|
if (!control.pending === arg)
|
|
819
846
|
return Promise.reject(Oops$2.StrictUpdate(arg));
|
|
820
847
|
}
|
|
821
|
-
else if (arg)
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
848
|
+
else if (arg) {
|
|
849
|
+
control.update(arg);
|
|
850
|
+
if (1 in arguments && arg in this)
|
|
851
|
+
if (typeof tag != "boolean")
|
|
852
|
+
this[arg](tag);
|
|
853
|
+
else if (tag)
|
|
854
|
+
this[arg]();
|
|
855
|
+
}
|
|
856
|
+
return {
|
|
857
|
+
then(callback) {
|
|
858
|
+
if (callback)
|
|
859
|
+
if (control.pending)
|
|
860
|
+
control.include(callback);
|
|
861
|
+
else
|
|
862
|
+
callback(false);
|
|
863
|
+
else
|
|
864
|
+
throw Oops$2.NoChaining();
|
|
865
|
+
}
|
|
866
|
+
};
|
|
827
867
|
}
|
|
828
868
|
destroy() {
|
|
829
|
-
|
|
830
|
-
this.willDestroy();
|
|
869
|
+
this.update("willDestroy", true);
|
|
831
870
|
}
|
|
832
871
|
toString() {
|
|
833
872
|
return this.constructor.name;
|
|
834
873
|
}
|
|
874
|
+
tap(path, expect) {
|
|
875
|
+
return useWatcher(this, path, expect);
|
|
876
|
+
}
|
|
835
877
|
static create(...args) {
|
|
836
878
|
const instance = new this(...args);
|
|
837
879
|
manage(instance);
|
|
838
880
|
return instance;
|
|
839
881
|
}
|
|
840
|
-
static
|
|
841
|
-
return
|
|
882
|
+
static new(args, callback) {
|
|
883
|
+
return useLazy(this, args, callback);
|
|
884
|
+
}
|
|
885
|
+
static use(args, callback) {
|
|
886
|
+
return useModel(this, args, callback);
|
|
842
887
|
}
|
|
843
888
|
static uses(props, only) {
|
|
844
|
-
return
|
|
889
|
+
return this.use([], instance => {
|
|
845
890
|
instance.import(props, only);
|
|
846
891
|
});
|
|
847
892
|
}
|
|
848
893
|
static using(props, only) {
|
|
849
|
-
const instance =
|
|
894
|
+
const instance = this.use([]);
|
|
850
895
|
instance.import(props, only);
|
|
851
896
|
return instance;
|
|
852
897
|
}
|
|
853
|
-
static
|
|
854
|
-
return
|
|
898
|
+
static find(strict) {
|
|
899
|
+
return useFromContext(this, strict);
|
|
855
900
|
}
|
|
856
901
|
static get(key) {
|
|
857
902
|
const instance = this.find(!!key);
|
|
@@ -864,31 +909,103 @@ class Model {
|
|
|
864
909
|
static tap(key, expect) {
|
|
865
910
|
return useWatcher(this.find(true), key, expect);
|
|
866
911
|
}
|
|
912
|
+
static isTypeof(maybe) {
|
|
913
|
+
return (typeof maybe == "function" &&
|
|
914
|
+
maybe.prototype instanceof this);
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
State.CONTROL = CONTROL;
|
|
918
|
+
State.STATE = STATE;
|
|
919
|
+
State.INIT = CREATE;
|
|
920
|
+
State.LOCAL = LOCAL;
|
|
921
|
+
|
|
922
|
+
const useComponentLifecycle = lifecycle("component");
|
|
923
|
+
class Model extends State {
|
|
924
|
+
constructor() {
|
|
925
|
+
super(false);
|
|
926
|
+
}
|
|
927
|
+
[CREATE](using) {
|
|
928
|
+
defer(using, "on");
|
|
929
|
+
defer(using, "effect");
|
|
930
|
+
return () => {
|
|
931
|
+
delete this.on;
|
|
932
|
+
delete this.effect;
|
|
933
|
+
};
|
|
934
|
+
}
|
|
935
|
+
on(subset, handler, squash, once) {
|
|
936
|
+
const control = manage(this);
|
|
937
|
+
const set = keys(control, subset);
|
|
938
|
+
const batch = {};
|
|
939
|
+
const remove = control.addListener(batch);
|
|
940
|
+
const callback = squash
|
|
941
|
+
? handler.bind(this)
|
|
942
|
+
: (frame) => {
|
|
943
|
+
for (const key of frame)
|
|
944
|
+
if (set.includes(key))
|
|
945
|
+
handler.call(this, control.state[key], key);
|
|
946
|
+
};
|
|
947
|
+
const handle = once
|
|
948
|
+
? (k) => { remove(); callback(k); }
|
|
949
|
+
: callback;
|
|
950
|
+
for (const key of set)
|
|
951
|
+
batch[key] = handle;
|
|
952
|
+
ensure(control, set);
|
|
953
|
+
return remove;
|
|
954
|
+
}
|
|
955
|
+
once(select, callback, squash) {
|
|
956
|
+
if (callback)
|
|
957
|
+
return this.on(select, callback, squash, true);
|
|
958
|
+
else
|
|
959
|
+
return new Promise(resolve => {
|
|
960
|
+
this.on(select, resolve, true, true);
|
|
961
|
+
});
|
|
962
|
+
}
|
|
963
|
+
effect(callback, select) {
|
|
964
|
+
const control = manage(this);
|
|
965
|
+
let target = this;
|
|
966
|
+
const effect = createEffect(callback);
|
|
967
|
+
const invoke = () => effect.call(target, target);
|
|
968
|
+
if (select) {
|
|
969
|
+
invoke();
|
|
970
|
+
return this.on(select, invoke, true);
|
|
971
|
+
}
|
|
972
|
+
else {
|
|
973
|
+
const sub = new Subscriber(control, invoke);
|
|
974
|
+
target = sub.proxy;
|
|
975
|
+
invoke();
|
|
976
|
+
return sub.commit();
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
tag(id) {
|
|
980
|
+
return useSubscriber(this, id);
|
|
981
|
+
}
|
|
982
|
+
static use(args, callback) {
|
|
983
|
+
const instance = useModel(this, args, callback);
|
|
984
|
+
useComponentLifecycle(instance[LOCAL]);
|
|
985
|
+
usePeerContext(instance.get);
|
|
986
|
+
return instance;
|
|
987
|
+
}
|
|
867
988
|
static tag(id) {
|
|
868
989
|
return useSubscriber(this.find(true), id);
|
|
869
990
|
}
|
|
870
991
|
static meta(path) {
|
|
871
992
|
return useWatcher(this, path);
|
|
872
993
|
}
|
|
873
|
-
static find(strict) {
|
|
874
|
-
return useFromContext(this, strict);
|
|
875
|
-
}
|
|
876
|
-
static isTypeof(maybe) {
|
|
877
|
-
return (typeof maybe == "function" &&
|
|
878
|
-
maybe.prototype instanceof this);
|
|
879
|
-
}
|
|
880
|
-
static get inherits() {
|
|
881
|
-
const I = getPrototypeOf(this);
|
|
882
|
-
if (I !== Model)
|
|
883
|
-
return I;
|
|
884
|
-
}
|
|
885
994
|
}
|
|
886
|
-
Model.STATE = STATE;
|
|
887
|
-
Model.CONTROL = CONTROL;
|
|
888
|
-
Model.LOCAL = LOCAL;
|
|
889
995
|
defineLazy(Model, CONTROL, function () {
|
|
890
996
|
return new Controller(this).start();
|
|
891
|
-
});
|
|
997
|
+
});
|
|
998
|
+
function defer(on, method) {
|
|
999
|
+
const { subject, waiting } = on;
|
|
1000
|
+
const real = subject[method];
|
|
1001
|
+
subject[method] = (...args) => {
|
|
1002
|
+
let done;
|
|
1003
|
+
waiting.push(() => {
|
|
1004
|
+
done = real.apply(subject, args);
|
|
1005
|
+
});
|
|
1006
|
+
return () => done();
|
|
1007
|
+
};
|
|
1008
|
+
}
|
|
892
1009
|
|
|
893
1010
|
const Parent = new WeakMap();
|
|
894
1011
|
const Oops$1 = issues({
|
|
@@ -897,7 +1014,14 @@ const Oops$1 = issues({
|
|
|
897
1014
|
UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
|
|
898
1015
|
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`
|
|
899
1016
|
});
|
|
900
|
-
|
|
1017
|
+
function bootstrap(object) {
|
|
1018
|
+
const breakdown = getOwnPropertyDescriptors(object);
|
|
1019
|
+
const control = new Model();
|
|
1020
|
+
for (const key in breakdown)
|
|
1021
|
+
defineProperty(control, key, breakdown[key]);
|
|
1022
|
+
return control;
|
|
1023
|
+
}
|
|
1024
|
+
const use = (input, argument) => attach(function use(key) {
|
|
901
1025
|
let instance;
|
|
902
1026
|
const update = (next) => {
|
|
903
1027
|
instance =
|
|
@@ -927,52 +1051,6 @@ const use = (input, argument) => child(function use(key) {
|
|
|
927
1051
|
this.manage(key, instance, update);
|
|
928
1052
|
return () => instance;
|
|
929
1053
|
});
|
|
930
|
-
function bootstrap(object) {
|
|
931
|
-
const breakdown = getOwnPropertyDescriptors(object);
|
|
932
|
-
const control = new Model();
|
|
933
|
-
for (const key in breakdown)
|
|
934
|
-
defineProperty(control, key, breakdown[key]);
|
|
935
|
-
return control;
|
|
936
|
-
}
|
|
937
|
-
const child = (from, name) => {
|
|
938
|
-
function child(key) {
|
|
939
|
-
const proxyCache = new WeakMap();
|
|
940
|
-
const getCurrent = from.call(this, key);
|
|
941
|
-
function subscribe(sub) {
|
|
942
|
-
let child;
|
|
943
|
-
function start() {
|
|
944
|
-
const instance = getCurrent();
|
|
945
|
-
if (instance) {
|
|
946
|
-
child = new Subscriber(instance, sub.onUpdate);
|
|
947
|
-
if (sub.active)
|
|
948
|
-
child.commit();
|
|
949
|
-
sub.dependant.add(child);
|
|
950
|
-
proxyCache.set(sub, child.proxy);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
function refresh() {
|
|
954
|
-
if (child) {
|
|
955
|
-
child.release();
|
|
956
|
-
sub.dependant.delete(child);
|
|
957
|
-
proxyCache.set(sub, undefined);
|
|
958
|
-
child = undefined;
|
|
959
|
-
}
|
|
960
|
-
start();
|
|
961
|
-
sub.onUpdate();
|
|
962
|
-
}
|
|
963
|
-
start();
|
|
964
|
-
sub.follow(key, refresh);
|
|
965
|
-
}
|
|
966
|
-
return (local) => {
|
|
967
|
-
if (!local)
|
|
968
|
-
return getCurrent();
|
|
969
|
-
if (!proxyCache.has(local))
|
|
970
|
-
subscribe(local);
|
|
971
|
-
return proxyCache.get(local);
|
|
972
|
-
};
|
|
973
|
-
}
|
|
974
|
-
return set(child, name || from.name);
|
|
975
|
-
};
|
|
976
1054
|
const parent = (Expects, required) => set(function parent() {
|
|
977
1055
|
const child = this.subject;
|
|
978
1056
|
const expected = Expects.name;
|
|
@@ -1003,10 +1081,19 @@ class Singleton extends Model {
|
|
|
1003
1081
|
Active.set(Type, instance);
|
|
1004
1082
|
return instance;
|
|
1005
1083
|
}
|
|
1006
|
-
static
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1084
|
+
static update(updates) {
|
|
1085
|
+
const instance = this.current || this.create();
|
|
1086
|
+
instance.import(updates);
|
|
1087
|
+
return instance.update();
|
|
1088
|
+
}
|
|
1089
|
+
static is() {
|
|
1090
|
+
return this.find(true);
|
|
1091
|
+
}
|
|
1092
|
+
static find(strict) {
|
|
1093
|
+
const instance = this.current;
|
|
1094
|
+
if (!instance && strict)
|
|
1095
|
+
throw Oops.GlobalDoesNotExist(this.name);
|
|
1096
|
+
return instance;
|
|
1010
1097
|
}
|
|
1011
1098
|
static reset() {
|
|
1012
1099
|
if (this.current)
|
|
@@ -1022,8 +1109,9 @@ exports.Consumer = Consumer;
|
|
|
1022
1109
|
exports.Model = Model;
|
|
1023
1110
|
exports.Provider = Provider;
|
|
1024
1111
|
exports.Singleton = Singleton;
|
|
1112
|
+
exports.State = State;
|
|
1025
1113
|
exports.act = act;
|
|
1026
|
-
exports.
|
|
1114
|
+
exports.attach = attach;
|
|
1027
1115
|
exports.default = Model;
|
|
1028
1116
|
exports.from = from;
|
|
1029
1117
|
exports.lazy = lazy;
|