@expressive/mvc 1.0.0-beta.34 → 1.0.0-beta.37
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 +582 -0
- package/lib/index.esm.js +833 -880
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +848 -888
- package/lib/index.js.map +1 -1
- package/package.json +9 -8
- package/types/context.d.ts +0 -57
- package/types/index.d.ts +0 -9
- package/types/instructions.d.ts +0 -339
- package/types/lifecycle.d.ts +0 -30
- package/types/model.d.ts +0 -528
- package/types/selector.ts +0 -47
- package/types/types.d.ts +0 -18
package/lib/index.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var React = require('react');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
|
+
|
|
9
|
+
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
6
10
|
|
|
7
11
|
class Issue extends Error {
|
|
8
12
|
constructor() {
|
|
@@ -13,9 +17,6 @@ class Issue extends Error {
|
|
|
13
17
|
warn() {
|
|
14
18
|
console.warn(this.message);
|
|
15
19
|
}
|
|
16
|
-
throw() {
|
|
17
|
-
throw this;
|
|
18
|
-
}
|
|
19
20
|
}
|
|
20
21
|
function issues(register) {
|
|
21
22
|
const Library = {};
|
|
@@ -24,10 +25,10 @@ function issues(register) {
|
|
|
24
25
|
return Library;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
const Oops$
|
|
28
|
+
const Oops$d = issues({
|
|
28
29
|
BadEffectCallback: () => `Callback for effect-callback may only return a function.`
|
|
29
30
|
});
|
|
30
|
-
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor,
|
|
31
|
+
const { assign, create, defineProperty, entries, getPrototypeOf, getOwnPropertyNames, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
31
32
|
function define(target, key, value) {
|
|
32
33
|
defineProperty(target, key, { value });
|
|
33
34
|
}
|
|
@@ -53,7 +54,7 @@ function createEffect(callback) {
|
|
|
53
54
|
if (unSet instanceof Promise)
|
|
54
55
|
unSet = undefined;
|
|
55
56
|
if (unSet && typeof unSet !== "function")
|
|
56
|
-
throw Oops$
|
|
57
|
+
throw Oops$d.BadEffectCallback();
|
|
57
58
|
};
|
|
58
59
|
}
|
|
59
60
|
function createValueEffect(callback) {
|
|
@@ -61,7 +62,7 @@ function createValueEffect(callback) {
|
|
|
61
62
|
return function (value) {
|
|
62
63
|
if (typeof unSet == "function")
|
|
63
64
|
unSet(value);
|
|
64
|
-
const out = callback.call(this, value);
|
|
65
|
+
const out = callback.call(this, value, this);
|
|
65
66
|
if (typeof out == "boolean")
|
|
66
67
|
return out;
|
|
67
68
|
if (!out || out instanceof Promise)
|
|
@@ -69,88 +70,235 @@ function createValueEffect(callback) {
|
|
|
69
70
|
if (typeof out == "function")
|
|
70
71
|
unSet = out;
|
|
71
72
|
else
|
|
72
|
-
throw Oops$
|
|
73
|
+
throw Oops$d.BadEffectCallback();
|
|
73
74
|
};
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
return
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const UPDATE = new WeakMap();
|
|
78
|
+
function applyUpdate(subject, keys) {
|
|
79
|
+
UPDATE.set(subject, keys);
|
|
80
|
+
return () => {
|
|
81
|
+
setTimeout(() => {
|
|
82
|
+
UPDATE.delete(subject);
|
|
83
|
+
}, 0);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const Oops$c = issues({
|
|
88
|
+
StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
|
|
89
|
+
NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
|
|
90
|
+
});
|
|
91
|
+
const READY = new WeakSet();
|
|
92
|
+
class Controller {
|
|
93
|
+
constructor(subject) {
|
|
94
|
+
this.subject = subject;
|
|
95
|
+
this.state = {};
|
|
96
|
+
this.frame = new Set();
|
|
97
|
+
this.waiting = new Set();
|
|
98
|
+
this.onDestroy = new Set();
|
|
99
|
+
this.followers = new Set();
|
|
100
|
+
this.proxy = Object.create(subject);
|
|
101
|
+
}
|
|
102
|
+
start() {
|
|
103
|
+
for (const key in this.subject)
|
|
104
|
+
this.manage(key);
|
|
105
|
+
this.emit([]);
|
|
106
|
+
}
|
|
107
|
+
stop() {
|
|
108
|
+
this.followers.clear();
|
|
109
|
+
this.onDestroy.forEach(x => x());
|
|
110
|
+
}
|
|
111
|
+
manage(key) {
|
|
112
|
+
const { proxy, state, subject } = this;
|
|
113
|
+
const { value: entry } = getOwnPropertyDescriptor(subject, key);
|
|
114
|
+
if (typeof entry == "function")
|
|
115
|
+
return;
|
|
116
|
+
let onGet;
|
|
117
|
+
let onSet;
|
|
118
|
+
let enumerable;
|
|
119
|
+
const instruction = Pending.get(entry);
|
|
120
|
+
if (instruction) {
|
|
121
|
+
Pending.delete(entry);
|
|
122
|
+
delete subject[key];
|
|
123
|
+
const desc = instruction.call(this, key, this);
|
|
124
|
+
if (!desc)
|
|
125
|
+
return;
|
|
126
|
+
if ("value" in desc)
|
|
127
|
+
state[key] = desc.value;
|
|
128
|
+
onSet = desc.set;
|
|
129
|
+
onGet = desc.get;
|
|
130
|
+
enumerable = desc.enumerable;
|
|
131
|
+
}
|
|
132
|
+
else
|
|
133
|
+
state[key] = entry;
|
|
134
|
+
const set = onSet !== false
|
|
135
|
+
? this.ref(key, onSet)
|
|
136
|
+
: undefined;
|
|
137
|
+
function get() {
|
|
138
|
+
const local = this[LOCAL];
|
|
139
|
+
const value = state[key];
|
|
140
|
+
if (local && !local.watch[key])
|
|
141
|
+
local.watch[key] = true;
|
|
142
|
+
return onGet ? onGet(value, local) : value;
|
|
143
|
+
}
|
|
144
|
+
setAlias(get, `tap ${key}`);
|
|
145
|
+
defineProperty(subject, key, {
|
|
146
|
+
enumerable,
|
|
147
|
+
set,
|
|
148
|
+
get: onGet
|
|
149
|
+
? () => onGet(state[key])
|
|
150
|
+
: () => state[key]
|
|
151
|
+
});
|
|
152
|
+
defineProperty(proxy, key, {
|
|
153
|
+
enumerable,
|
|
154
|
+
set,
|
|
155
|
+
get
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
ref(key, handler) {
|
|
159
|
+
const { state, subject } = this;
|
|
160
|
+
return (value) => {
|
|
161
|
+
if (state[key] == value)
|
|
162
|
+
return;
|
|
163
|
+
if (handler)
|
|
164
|
+
switch (handler.call(subject, value, state)) {
|
|
165
|
+
case true:
|
|
166
|
+
this.update(key);
|
|
167
|
+
case false:
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.update(key, value);
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
addListener(listener) {
|
|
174
|
+
this.followers.add(listener);
|
|
175
|
+
return () => {
|
|
176
|
+
this.followers.delete(listener);
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
emit(keys) {
|
|
180
|
+
const waiting = [...this.waiting];
|
|
181
|
+
this.waiting.clear();
|
|
182
|
+
applyUpdate(this.subject, keys)();
|
|
183
|
+
for (const callback of waiting)
|
|
184
|
+
try {
|
|
185
|
+
callback(keys);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
console.error(err);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
update(key, value) {
|
|
192
|
+
if (1 in arguments)
|
|
193
|
+
this.state[key] = value;
|
|
194
|
+
if (this.frame.has(key))
|
|
195
|
+
return;
|
|
196
|
+
if (!this.frame.size)
|
|
197
|
+
setTimeout(() => {
|
|
198
|
+
flush(this);
|
|
199
|
+
const keys = Object.freeze([...this.frame]);
|
|
200
|
+
this.frame.clear();
|
|
201
|
+
this.emit(keys);
|
|
202
|
+
}, 0);
|
|
203
|
+
this.frame.add(key);
|
|
204
|
+
for (const callback of this.followers) {
|
|
205
|
+
const event = callback(key, this);
|
|
206
|
+
if (typeof event == "function")
|
|
207
|
+
this.waiting.add(event);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
requestUpdate(arg) {
|
|
211
|
+
if (typeof arg == "function") {
|
|
212
|
+
this.waiting.add(arg);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (typeof arg == "boolean" && arg !== this.frame.size > 0)
|
|
216
|
+
return Promise.reject(Oops$c.StrictUpdate(arg));
|
|
217
|
+
return {
|
|
218
|
+
then: (callback) => {
|
|
219
|
+
if (callback)
|
|
220
|
+
if (this.frame.size)
|
|
221
|
+
this.waiting.add(callback);
|
|
222
|
+
else
|
|
223
|
+
callback(false);
|
|
224
|
+
else
|
|
225
|
+
throw Oops$c.NoChaining();
|
|
89
226
|
}
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function control(subject, cb) {
|
|
231
|
+
let control = subject[CONTROL];
|
|
232
|
+
const ready = READY.has(control);
|
|
233
|
+
if (!control) {
|
|
234
|
+
control = new Controller(subject);
|
|
235
|
+
define(subject, CONTROL, control);
|
|
236
|
+
}
|
|
237
|
+
if (!cb) {
|
|
238
|
+
if (!ready) {
|
|
239
|
+
READY.add(control);
|
|
240
|
+
control.start();
|
|
241
|
+
}
|
|
242
|
+
return control;
|
|
243
|
+
}
|
|
244
|
+
if (!ready) {
|
|
245
|
+
let done;
|
|
246
|
+
control.requestUpdate(() => {
|
|
247
|
+
done = cb(control);
|
|
90
248
|
});
|
|
91
|
-
|
|
92
|
-
|
|
249
|
+
return () => done && done();
|
|
250
|
+
}
|
|
251
|
+
return cb(control);
|
|
93
252
|
}
|
|
94
253
|
|
|
95
254
|
class Subscriber {
|
|
96
255
|
constructor(parent, onUpdate) {
|
|
97
256
|
this.onUpdate = onUpdate;
|
|
98
257
|
this.active = false;
|
|
99
|
-
this.using = {};
|
|
100
258
|
this.dependant = new Set();
|
|
259
|
+
this.watch = {};
|
|
101
260
|
if (!(parent instanceof Controller))
|
|
102
|
-
parent =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
define(
|
|
107
|
-
|
|
108
|
-
const update = [];
|
|
109
|
-
this.notify = keys => {
|
|
110
|
-
update.splice(0, update.length, ...keys.filter(k => k in this.using));
|
|
111
|
-
};
|
|
112
|
-
return update;
|
|
113
|
-
});
|
|
114
|
-
for (const key in parent.state)
|
|
115
|
-
this.spy(key);
|
|
116
|
-
}
|
|
117
|
-
spy(key) {
|
|
118
|
-
const { proxy } = this;
|
|
119
|
-
const existing = getOwnPropertyDescriptor(this.source, key);
|
|
120
|
-
const isUsing = () => {
|
|
121
|
-
this.using[key] = true;
|
|
122
|
-
delete proxy[key];
|
|
123
|
-
return proxy[key];
|
|
124
|
-
};
|
|
125
|
-
setAlias(isUsing, `tap ${key}`);
|
|
126
|
-
defineProperty(proxy, key, {
|
|
127
|
-
set: existing.set,
|
|
128
|
-
get: isUsing,
|
|
261
|
+
parent = control(parent);
|
|
262
|
+
let reset;
|
|
263
|
+
const proxy = create(parent.proxy);
|
|
264
|
+
const controller = parent;
|
|
265
|
+
define(proxy, LOCAL, this);
|
|
266
|
+
defineProperty(this, "proxy", {
|
|
129
267
|
configurable: true,
|
|
130
|
-
|
|
268
|
+
get() {
|
|
269
|
+
if (reset)
|
|
270
|
+
setTimeout(reset, 0);
|
|
271
|
+
return proxy;
|
|
272
|
+
}
|
|
131
273
|
});
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const onDone = this.parent.addListener((key, source) => {
|
|
135
|
-
const handler = this.using[key];
|
|
274
|
+
const onEvent = (key) => {
|
|
275
|
+
const handler = this.watch[key];
|
|
136
276
|
if (!handler)
|
|
137
277
|
return;
|
|
138
278
|
if (typeof handler == "function")
|
|
139
279
|
handler();
|
|
140
|
-
const notify = this.onUpdate(key,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
280
|
+
const notify = this.onUpdate(key, controller);
|
|
281
|
+
const getWhy = (keys) => {
|
|
282
|
+
reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
|
|
283
|
+
};
|
|
284
|
+
if (notify) {
|
|
285
|
+
controller.requestUpdate(getWhy);
|
|
286
|
+
controller.requestUpdate(notify);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
this.commit = () => {
|
|
290
|
+
const release = controller.addListener(onEvent);
|
|
291
|
+
this.active = true;
|
|
292
|
+
this.dependant.forEach(x => x.commit());
|
|
293
|
+
return this.release = () => {
|
|
294
|
+
this.dependant.forEach(x => x.release());
|
|
295
|
+
release();
|
|
296
|
+
};
|
|
149
297
|
};
|
|
150
298
|
}
|
|
151
299
|
}
|
|
152
300
|
|
|
153
|
-
const Oops$
|
|
301
|
+
const Oops$b = issues({
|
|
154
302
|
ComputeFailed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
|
|
155
303
|
ComputedEarly: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
|
|
156
304
|
});
|
|
@@ -168,15 +316,12 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
168
316
|
USED.set(parent, register);
|
|
169
317
|
}
|
|
170
318
|
register.set(key, info);
|
|
171
|
-
const current = getter
|
|
172
|
-
? () => getter(parent, key)
|
|
173
|
-
: () => state[key];
|
|
174
319
|
function compute(initial) {
|
|
175
320
|
try {
|
|
176
321
|
return setter.call(sub.proxy, sub.proxy);
|
|
177
322
|
}
|
|
178
323
|
catch (err) {
|
|
179
|
-
Oops$
|
|
324
|
+
Oops$b.ComputeFailed(subject, key, !!initial).warn();
|
|
180
325
|
throw err;
|
|
181
326
|
}
|
|
182
327
|
}
|
|
@@ -212,44 +357,40 @@ function prepare(parent, key, source, setter, getter) {
|
|
|
212
357
|
value: undefined,
|
|
213
358
|
writable: true
|
|
214
359
|
});
|
|
215
|
-
defineProperty(subject, key, {
|
|
216
|
-
enumerable: true,
|
|
217
|
-
configurable: true,
|
|
218
|
-
get: current
|
|
219
|
-
});
|
|
220
360
|
try {
|
|
221
|
-
state[key] = compute(true);
|
|
361
|
+
return state[key] = compute(true);
|
|
222
362
|
}
|
|
223
363
|
catch (e) {
|
|
224
364
|
if (early)
|
|
225
|
-
Oops$
|
|
365
|
+
Oops$b.ComputedEarly(key).warn();
|
|
226
366
|
throw e;
|
|
227
367
|
}
|
|
228
368
|
finally {
|
|
229
369
|
sub.commit();
|
|
230
|
-
for (const key in sub.
|
|
370
|
+
for (const key in sub.watch) {
|
|
231
371
|
const peer = register.get(key);
|
|
232
372
|
if (peer && peer.priority >= info.priority)
|
|
233
373
|
info.priority = peer.priority + 1;
|
|
234
374
|
}
|
|
235
375
|
}
|
|
236
|
-
return current();
|
|
237
376
|
}
|
|
238
377
|
setAlias(update, `try ${key}`);
|
|
239
378
|
setAlias(create, `new ${key}`);
|
|
240
379
|
setAlias(setter, `run ${key}`);
|
|
241
380
|
INIT.add(create);
|
|
242
381
|
INFO.set(update, info);
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
382
|
+
defineProperty(state, key, {
|
|
383
|
+
get: create,
|
|
384
|
+
configurable: true,
|
|
385
|
+
enumerable: true
|
|
386
|
+
});
|
|
387
|
+
return getter
|
|
388
|
+
? () => getter(parent, key)
|
|
389
|
+
: {};
|
|
249
390
|
}
|
|
250
391
|
function ensure(on, keys) {
|
|
251
392
|
for (const key of keys) {
|
|
252
|
-
const desc = getOwnPropertyDescriptor(on.
|
|
393
|
+
const desc = getOwnPropertyDescriptor(on.state, key);
|
|
253
394
|
const getter = desc && desc.get;
|
|
254
395
|
if (INIT.has(getter))
|
|
255
396
|
getter(true);
|
|
@@ -270,377 +411,212 @@ function flush(on) {
|
|
|
270
411
|
KEYS.delete(on);
|
|
271
412
|
}
|
|
272
413
|
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
"willDestroy",
|
|
283
|
-
...values(Lifecycle)
|
|
284
|
-
];
|
|
285
|
-
function lifecycle(prefix) {
|
|
286
|
-
const type = eventsFor(prefix);
|
|
287
|
-
return function useLifecycle(sub, tag) {
|
|
288
|
-
const emit = react.useMemo(() => {
|
|
289
|
-
const subject = sub.source;
|
|
290
|
-
const id = typeof tag == "function" ? tag(subject) : tag;
|
|
291
|
-
return (name) => {
|
|
292
|
-
for (const key of [name, type(name)])
|
|
293
|
-
subject.update(key, id);
|
|
294
|
-
};
|
|
295
|
-
}, [sub, tag]);
|
|
296
|
-
emit(Lifecycle.WILL_RENDER);
|
|
297
|
-
emit(sub.active
|
|
298
|
-
? Lifecycle.WILL_UPDATE
|
|
299
|
-
: Lifecycle.WILL_MOUNT);
|
|
300
|
-
react.useLayoutEffect(() => {
|
|
301
|
-
sub.commit();
|
|
302
|
-
emit(Lifecycle.DID_MOUNT);
|
|
303
|
-
return () => {
|
|
304
|
-
emit(Lifecycle.WILL_UNMOUNT);
|
|
305
|
-
sub.release();
|
|
306
|
-
};
|
|
307
|
-
}, [sub]);
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
function eventsFor(prefix) {
|
|
311
|
-
const map = new Map();
|
|
312
|
-
for (const name of values(Lifecycle)) {
|
|
313
|
-
const alias = prefix + name[0].toUpperCase() + name.slice(1);
|
|
314
|
-
lifecycleEvents.push(alias);
|
|
315
|
-
map.set(name, alias);
|
|
414
|
+
const CONTROL = Symbol("CONTROL");
|
|
415
|
+
const WHY = Symbol("UPDATE");
|
|
416
|
+
const LOCAL = Symbol("LOCAL");
|
|
417
|
+
const STATE = Symbol("STATE");
|
|
418
|
+
class Model {
|
|
419
|
+
constructor() {
|
|
420
|
+
define(this, CONTROL, new Controller(this));
|
|
421
|
+
define(this, "get", this);
|
|
422
|
+
define(this, "set", this);
|
|
316
423
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
424
|
+
get [STATE]() {
|
|
425
|
+
return this[CONTROL].state;
|
|
426
|
+
}
|
|
427
|
+
get [WHY]() {
|
|
428
|
+
return UPDATE.get(this);
|
|
429
|
+
}
|
|
430
|
+
on(select, handler, squash, once) {
|
|
431
|
+
return control(this, control => {
|
|
432
|
+
if (typeof select == "function")
|
|
433
|
+
return control.addListener(select);
|
|
434
|
+
const keys = typeof select == "string" ? [select] :
|
|
435
|
+
!select.length ? getOwnPropertyNames(control.state) :
|
|
436
|
+
select;
|
|
437
|
+
ensure(control, keys);
|
|
438
|
+
const callback = squash
|
|
439
|
+
? handler.bind(this)
|
|
440
|
+
: frame => frame
|
|
441
|
+
.filter(k => keys.includes(k))
|
|
442
|
+
.forEach(k => handler.call(this, control.state[k], k));
|
|
443
|
+
const trigger = once
|
|
444
|
+
? frame => { remove(); callback(frame); }
|
|
445
|
+
: callback;
|
|
446
|
+
const remove = control.addListener(key => {
|
|
447
|
+
if (keys.includes(key))
|
|
448
|
+
return trigger;
|
|
449
|
+
});
|
|
450
|
+
return remove;
|
|
451
|
+
});
|
|
341
452
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
this.state = {};
|
|
349
|
-
this.frame = new Set();
|
|
350
|
-
this.waiting = new Set();
|
|
351
|
-
this.followers = new Set();
|
|
453
|
+
once(select, callback, squash) {
|
|
454
|
+
if (callback)
|
|
455
|
+
return this.on(select, callback, squash, true);
|
|
456
|
+
return new Promise(resolve => {
|
|
457
|
+
this.on(select, resolve, true, true);
|
|
458
|
+
});
|
|
352
459
|
}
|
|
353
|
-
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
460
|
+
effect(callback, select) {
|
|
461
|
+
const effect = createEffect(callback);
|
|
462
|
+
return control(this, control => {
|
|
463
|
+
if (!select) {
|
|
464
|
+
const sub = new Subscriber(control, () => invoke);
|
|
465
|
+
const invoke = () => {
|
|
466
|
+
const x = sub.proxy;
|
|
467
|
+
effect.call(x, x);
|
|
468
|
+
};
|
|
469
|
+
invoke();
|
|
470
|
+
return sub.commit();
|
|
471
|
+
}
|
|
472
|
+
const invoke = () => {
|
|
473
|
+
effect.call(this.get, this.get);
|
|
474
|
+
};
|
|
475
|
+
invoke();
|
|
476
|
+
if (!select.length) {
|
|
477
|
+
control.onDestroy.add(invoke);
|
|
478
|
+
return () => {
|
|
479
|
+
control.onDestroy.delete(invoke);
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
return control.addListener(key => {
|
|
483
|
+
if (select.includes(key))
|
|
484
|
+
return invoke;
|
|
485
|
+
});
|
|
361
486
|
});
|
|
362
|
-
return control;
|
|
363
487
|
}
|
|
364
|
-
|
|
365
|
-
|
|
488
|
+
// TODO: account for exotic properties
|
|
489
|
+
import(source, select) {
|
|
490
|
+
const { subject } = control(this);
|
|
491
|
+
if (!select)
|
|
492
|
+
select = getOwnPropertyNames(subject);
|
|
493
|
+
for (const key of select)
|
|
494
|
+
if (key in source)
|
|
495
|
+
this[key] = source[key];
|
|
366
496
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
497
|
+
export(subset) {
|
|
498
|
+
const { state } = control(this);
|
|
499
|
+
const output = {};
|
|
500
|
+
if (!subset)
|
|
501
|
+
subset = getOwnPropertyNames(state);
|
|
502
|
+
for (const key of subset)
|
|
503
|
+
output[key] = state[key];
|
|
504
|
+
return output;
|
|
370
505
|
}
|
|
371
|
-
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
if (
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
else if (typeof value !== "function" || /^[A-Z]/.test(key))
|
|
384
|
-
this.manage(key, value);
|
|
506
|
+
update(arg, tag) {
|
|
507
|
+
const target = control(this);
|
|
508
|
+
if (typeof arg == "string") {
|
|
509
|
+
target.update(arg);
|
|
510
|
+
if (1 in arguments && arg in this) {
|
|
511
|
+
const method = this[arg];
|
|
512
|
+
if (typeof method == "function")
|
|
513
|
+
if (typeof tag != "boolean")
|
|
514
|
+
method.call(this, tag);
|
|
515
|
+
else if (tag)
|
|
516
|
+
method.call(this);
|
|
385
517
|
}
|
|
518
|
+
arg = undefined;
|
|
386
519
|
}
|
|
387
|
-
|
|
388
|
-
return this;
|
|
389
|
-
}
|
|
390
|
-
select(using) {
|
|
391
|
-
const keys = getOwnPropertyNames(this.state);
|
|
392
|
-
return using
|
|
393
|
-
? selectRecursive(using, keys.concat(lifecycleEvents))
|
|
394
|
-
: keys;
|
|
395
|
-
}
|
|
396
|
-
manage(key, initial, effect) {
|
|
397
|
-
const { state, subject } = this;
|
|
398
|
-
state[key] = initial;
|
|
399
|
-
defineProperty(subject, key, {
|
|
400
|
-
enumerable: true,
|
|
401
|
-
configurable: true,
|
|
402
|
-
get: () => state[key],
|
|
403
|
-
set: this.setter(key, effect)
|
|
404
|
-
});
|
|
520
|
+
return target.requestUpdate(arg);
|
|
405
521
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
if (handler)
|
|
412
|
-
switch (handler.call(subject, value)) {
|
|
413
|
-
case true:
|
|
414
|
-
this.update(key);
|
|
415
|
-
case false:
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
this.update(key, value);
|
|
419
|
-
};
|
|
522
|
+
/**
|
|
523
|
+
* Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
|
|
524
|
+
*/
|
|
525
|
+
destroy() {
|
|
526
|
+
control(this).stop();
|
|
420
527
|
}
|
|
421
|
-
|
|
422
|
-
this.
|
|
423
|
-
return () => {
|
|
424
|
-
this.followers.delete(listener);
|
|
425
|
-
};
|
|
528
|
+
toString() {
|
|
529
|
+
return this.constructor.name;
|
|
426
530
|
}
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
531
|
+
/**
|
|
532
|
+
* Creates a new instance of this controller.
|
|
533
|
+
*
|
|
534
|
+
* Beyond `new this(...)`, method will activate managed-state.
|
|
535
|
+
*
|
|
536
|
+
* @param args - arguments sent to constructor
|
|
537
|
+
*/
|
|
538
|
+
static create(...args) {
|
|
539
|
+
const instance = new this(...args);
|
|
540
|
+
control(instance);
|
|
541
|
+
return instance;
|
|
437
542
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
value: keys
|
|
447
|
-
});
|
|
448
|
-
handle.forEach(callback => {
|
|
449
|
-
try {
|
|
450
|
-
callback(keys);
|
|
451
|
-
}
|
|
452
|
-
catch (e) { }
|
|
453
|
-
});
|
|
543
|
+
/**
|
|
544
|
+
* Static equivalent of `x instanceof this`.
|
|
545
|
+
*
|
|
546
|
+
* Will determine if provided class is a subtype of this one.
|
|
547
|
+
*/
|
|
548
|
+
static isTypeof(maybe) {
|
|
549
|
+
return (typeof maybe == "function" &&
|
|
550
|
+
maybe.prototype instanceof this);
|
|
454
551
|
}
|
|
455
552
|
}
|
|
456
|
-
function
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
553
|
+
defineLazy(Model, CONTROL, function () {
|
|
554
|
+
return new Controller(this);
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
const Pending = new Map();
|
|
558
|
+
function apply(fn, label) {
|
|
559
|
+
const name = label || fn.name || "pending";
|
|
560
|
+
const placeholder = Symbol(`${name} instruction`);
|
|
561
|
+
function setup(key) {
|
|
562
|
+
let output = fn.call(this, key, this);
|
|
563
|
+
if (!output)
|
|
564
|
+
return;
|
|
565
|
+
if ("explicit" in output) {
|
|
566
|
+
defineProperty(this.subject, key, output);
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
if ("recursive" in output)
|
|
570
|
+
output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
|
|
571
|
+
if (typeof output == "function")
|
|
572
|
+
return { get: output };
|
|
463
573
|
else
|
|
464
|
-
return
|
|
574
|
+
return output;
|
|
465
575
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
function
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
if (sub.active)
|
|
480
|
-
child.commit();
|
|
481
|
-
sub.dependant.add(child);
|
|
482
|
-
context.set(sub, child.proxy);
|
|
483
|
-
}
|
|
576
|
+
Pending.set(placeholder, setup);
|
|
577
|
+
return placeholder;
|
|
578
|
+
}
|
|
579
|
+
function recursive(source, key) {
|
|
580
|
+
const context = new WeakMap();
|
|
581
|
+
const subscribe = (parent) => {
|
|
582
|
+
let child;
|
|
583
|
+
const init = () => {
|
|
584
|
+
if (child) {
|
|
585
|
+
child.release();
|
|
586
|
+
parent.dependant.delete(child);
|
|
587
|
+
context.set(parent, undefined);
|
|
588
|
+
child = undefined;
|
|
484
589
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
start();
|
|
590
|
+
const value = source.state[key];
|
|
591
|
+
if (value && CONTROL in value) {
|
|
592
|
+
child = new Subscriber(value, parent.onUpdate);
|
|
593
|
+
if (parent.active)
|
|
594
|
+
child.commit();
|
|
595
|
+
parent.dependant.add(child);
|
|
596
|
+
context.set(parent, child.proxy);
|
|
493
597
|
}
|
|
494
|
-
start();
|
|
495
|
-
sub.using[key] = restart;
|
|
496
|
-
}
|
|
497
|
-
return (local) => {
|
|
498
|
-
if (!local)
|
|
499
|
-
return current();
|
|
500
|
-
if (!context.has(local))
|
|
501
|
-
subscribe(local);
|
|
502
|
-
return context.get(local);
|
|
503
598
|
};
|
|
504
|
-
|
|
599
|
+
init();
|
|
600
|
+
parent.watch[key] = init;
|
|
601
|
+
};
|
|
602
|
+
return (value, local) => {
|
|
603
|
+
if (!local)
|
|
604
|
+
return value;
|
|
605
|
+
if (!context.has(local))
|
|
606
|
+
subscribe(local);
|
|
607
|
+
return context.get(local);
|
|
608
|
+
};
|
|
505
609
|
}
|
|
506
610
|
|
|
507
|
-
const Oops$
|
|
508
|
-
|
|
509
|
-
BadFactory: () => `Set instruction can only accept a factory or undefined.`,
|
|
510
|
-
FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
611
|
+
const Oops$a = issues({
|
|
612
|
+
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
|
|
511
613
|
});
|
|
512
|
-
function lazy(value) {
|
|
513
|
-
return apply(function lazy(key) {
|
|
514
|
-
const source = this.subject;
|
|
515
|
-
source[key] = value;
|
|
516
|
-
defineProperty(this.state, key, {
|
|
517
|
-
get: () => source[key]
|
|
518
|
-
});
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
function set(factory, argument) {
|
|
522
|
-
return apply(function set(key) {
|
|
523
|
-
let onSet;
|
|
524
|
-
let onGet;
|
|
525
|
-
const required = argument === true || argument === undefined;
|
|
526
|
-
if (factory === undefined)
|
|
527
|
-
onGet = () => pendingValue(this, key);
|
|
528
|
-
else if (typeof factory !== "function")
|
|
529
|
-
throw Oops$7.BadFactory();
|
|
530
|
-
else {
|
|
531
|
-
onGet = pendingFactory(this, key, factory);
|
|
532
|
-
if (required)
|
|
533
|
-
try {
|
|
534
|
-
onGet();
|
|
535
|
-
}
|
|
536
|
-
catch (err) {
|
|
537
|
-
if (err instanceof Promise)
|
|
538
|
-
;
|
|
539
|
-
else {
|
|
540
|
-
Oops$7.FactoryFailed(this.subject, key).warn();
|
|
541
|
-
throw err;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
if (typeof argument == "function")
|
|
546
|
-
onSet = createValueEffect(argument);
|
|
547
|
-
else if (required)
|
|
548
|
-
onSet = (value) => {
|
|
549
|
-
if (value === undefined)
|
|
550
|
-
throw Oops$7.NonOptional(this.subject, key);
|
|
551
|
-
};
|
|
552
|
-
return {
|
|
553
|
-
set: this.setter(key, onSet),
|
|
554
|
-
get: onGet
|
|
555
|
-
};
|
|
556
|
-
});
|
|
557
|
-
}
|
|
558
|
-
function on(initial, onUpdate) {
|
|
559
|
-
return set(initial && (() => initial), onUpdate);
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
const Oops$6 = issues({
|
|
563
|
-
CantAttachGlobal: (parent, child) => `Singleton '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
564
|
-
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.`
|
|
565
|
-
});
|
|
566
|
-
const PendingContext = new WeakMap();
|
|
567
|
-
const ContextWasUsed = new WeakMap();
|
|
568
|
-
function tap(type, argument) {
|
|
569
|
-
return child(function tap(key) {
|
|
570
|
-
return pendingAccess(this.subject, type, key, argument);
|
|
571
|
-
});
|
|
572
|
-
}
|
|
573
|
-
function pendingAccess(from, type, key, argument) {
|
|
574
|
-
if ("current" in type)
|
|
575
|
-
return () => type.current;
|
|
576
|
-
if ("current" in from.constructor)
|
|
577
|
-
throw Oops$6.CantAttachGlobal(from, type.name);
|
|
578
|
-
let instance;
|
|
579
|
-
getPending(from).push(context => {
|
|
580
|
-
instance = context.get(type);
|
|
581
|
-
if (typeof argument == "function") {
|
|
582
|
-
if (argument(instance) === false)
|
|
583
|
-
instance = undefined;
|
|
584
|
-
}
|
|
585
|
-
else if (!instance && argument)
|
|
586
|
-
throw Oops$6.AmbientRequired(type.name, from, key);
|
|
587
|
-
});
|
|
588
|
-
return () => instance;
|
|
589
|
-
}
|
|
590
|
-
function usePeerContext(subject) {
|
|
591
|
-
if (ContextWasUsed.has(subject)) {
|
|
592
|
-
if (ContextWasUsed.get(subject))
|
|
593
|
-
useLookup();
|
|
594
|
-
return;
|
|
595
|
-
}
|
|
596
|
-
const pending = PendingContext.get(subject);
|
|
597
|
-
if (pending) {
|
|
598
|
-
const local = useLookup();
|
|
599
|
-
for (const init of pending)
|
|
600
|
-
init(local);
|
|
601
|
-
PendingContext.delete(subject);
|
|
602
|
-
}
|
|
603
|
-
ContextWasUsed.set(subject, !!pending);
|
|
604
|
-
}
|
|
605
|
-
function getPending(subject) {
|
|
606
|
-
let pending = PendingContext.get(subject);
|
|
607
|
-
if (!pending)
|
|
608
|
-
PendingContext.set(subject, pending = []);
|
|
609
|
-
return pending;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
const Oops$5 = issues({
|
|
613
|
-
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`,
|
|
614
|
-
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
615
|
-
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
616
|
-
});
|
|
617
|
-
function createRef(key, cb) {
|
|
618
|
-
const refObjectFunction = this.setter(key, cb && createValueEffect(cb));
|
|
619
|
-
defineProperty(refObjectFunction, "current", {
|
|
620
|
-
set: refObjectFunction,
|
|
621
|
-
get: () => this.state[key]
|
|
622
|
-
});
|
|
623
|
-
return refObjectFunction;
|
|
624
|
-
}
|
|
625
|
-
function ref(arg) {
|
|
626
|
-
return apply(function ref(key) {
|
|
627
|
-
let value = {};
|
|
628
|
-
if (typeof arg == "object") {
|
|
629
|
-
const source = manage(arg);
|
|
630
|
-
for (const key in source.state)
|
|
631
|
-
defineLazy(value, key, createRef.bind(source, key));
|
|
632
|
-
}
|
|
633
|
-
else
|
|
634
|
-
value = createRef.call(this, key, arg);
|
|
635
|
-
return { value };
|
|
636
|
-
});
|
|
637
|
-
}
|
|
638
614
|
function act(task) {
|
|
639
615
|
return apply(function act(key) {
|
|
640
616
|
let pending = false;
|
|
641
617
|
const invoke = (...args) => {
|
|
642
618
|
if (pending)
|
|
643
|
-
return Promise.reject(Oops$
|
|
619
|
+
return Promise.reject(Oops$a.DuplicateAction(key));
|
|
644
620
|
pending = true;
|
|
645
621
|
this.update(key);
|
|
646
622
|
return new Promise(res => {
|
|
@@ -657,50 +633,14 @@ function act(task) {
|
|
|
657
633
|
});
|
|
658
634
|
return {
|
|
659
635
|
value: invoke,
|
|
660
|
-
|
|
636
|
+
set: false
|
|
661
637
|
};
|
|
662
638
|
});
|
|
663
|
-
}
|
|
664
|
-
function from(source, setter, argument) {
|
|
665
|
-
return apply(function from(key) {
|
|
666
|
-
let getSource;
|
|
667
|
-
const { subject } = this;
|
|
668
|
-
const getter = argument === true
|
|
669
|
-
? pendingValue
|
|
670
|
-
: argument || undefined;
|
|
671
|
-
// Easy mistake, using a peer, will always be unresolved.
|
|
672
|
-
if (typeof source == "symbol")
|
|
673
|
-
throw Oops$5.PeerNotAllowed(subject, key);
|
|
674
|
-
// replace source controller in-case different
|
|
675
|
-
if (typeof source == "object")
|
|
676
|
-
getSource = () => manage(source);
|
|
677
|
-
// specifically an arrow function (getter factory)
|
|
678
|
-
else if (!source.prototype) {
|
|
679
|
-
setter = source.call(subject, key);
|
|
680
|
-
getSource = () => this;
|
|
681
|
-
}
|
|
682
|
-
// is a peer Model (constructor)
|
|
683
|
-
else if (Model.isTypeof(source))
|
|
684
|
-
getSource = pendingAccess(subject, source, key, true);
|
|
685
|
-
// Regular function is too ambiguous so not allowed.
|
|
686
|
-
else
|
|
687
|
-
throw Oops$5.BadComputedSource(subject, key, source);
|
|
688
|
-
prepare(this, key, getSource, setter, getter);
|
|
689
|
-
});
|
|
690
639
|
}
|
|
691
640
|
|
|
692
|
-
const Oops$
|
|
641
|
+
const Oops$9 = issues({
|
|
693
642
|
ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
694
643
|
});
|
|
695
|
-
/* deprecated - ignore coverage */
|
|
696
|
-
/* istanbul ignore next */
|
|
697
|
-
function pending(source, compute) {
|
|
698
|
-
if (source === undefined)
|
|
699
|
-
return set();
|
|
700
|
-
if (typeof source == "function" && !source.prototype)
|
|
701
|
-
return set(source);
|
|
702
|
-
return from(source, compute, true);
|
|
703
|
-
}
|
|
704
644
|
/**
|
|
705
645
|
* Get value, suspend instead if undefined.
|
|
706
646
|
*
|
|
@@ -732,7 +672,7 @@ function pendingFactory(via, key, fn) {
|
|
|
732
672
|
throw error = err;
|
|
733
673
|
}
|
|
734
674
|
if (output instanceof Promise) {
|
|
735
|
-
const issue = Oops$
|
|
675
|
+
const issue = Oops$9.ValueNotReady(subject, key);
|
|
736
676
|
output
|
|
737
677
|
.catch(err => error = err)
|
|
738
678
|
.then(out => state[key] = out)
|
|
@@ -748,7 +688,7 @@ function pendingFactory(via, key, fn) {
|
|
|
748
688
|
};
|
|
749
689
|
}
|
|
750
690
|
function suspend(source, key) {
|
|
751
|
-
const error = Oops$
|
|
691
|
+
const error = Oops$9.ValueNotReady(source.subject, key);
|
|
752
692
|
const promise = new Promise(resolve => {
|
|
753
693
|
const release = source.addListener(forKey => {
|
|
754
694
|
if (forKey == key)
|
|
@@ -768,99 +708,153 @@ function suspend(source, key) {
|
|
|
768
708
|
});
|
|
769
709
|
}
|
|
770
710
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
if (
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
const value = source[focus];
|
|
795
|
-
if (value === undefined && expected)
|
|
796
|
-
throw suspend(sub.parent, focus);
|
|
797
|
-
return value;
|
|
798
|
-
}
|
|
799
|
-
});
|
|
711
|
+
const Oops$8 = issues({
|
|
712
|
+
BadComputedSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
|
|
713
|
+
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`
|
|
714
|
+
});
|
|
715
|
+
function from(source, setter, arg) {
|
|
716
|
+
return apply(function from(key) {
|
|
717
|
+
const { subject } = this;
|
|
718
|
+
let getSource;
|
|
719
|
+
let getter;
|
|
720
|
+
if (arg === true || setter === true)
|
|
721
|
+
getter = pendingValue;
|
|
722
|
+
if (typeof setter == "boolean")
|
|
723
|
+
setter = undefined;
|
|
724
|
+
// Easy mistake, using a peer, will always be unresolved.
|
|
725
|
+
if (typeof source == "symbol")
|
|
726
|
+
throw Oops$8.PeerNotAllowed(subject, key);
|
|
727
|
+
// replace source controller in-case it is different
|
|
728
|
+
if (typeof source == "object")
|
|
729
|
+
getSource = () => control(source);
|
|
730
|
+
// specifically an arrow function (getter factory)
|
|
731
|
+
else if (!source.prototype) {
|
|
732
|
+
setter = source.call(subject, key);
|
|
733
|
+
getSource = () => this;
|
|
800
734
|
}
|
|
801
|
-
|
|
735
|
+
// Regular function is too ambiguous so not allowed.
|
|
736
|
+
else
|
|
737
|
+
throw Oops$8.BadComputedSource(subject, key, source);
|
|
738
|
+
return prepare(this, key, getSource, setter, getter);
|
|
802
739
|
});
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
function
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
let retry;
|
|
813
|
-
const set = (next) => {
|
|
814
|
-
value = next;
|
|
815
|
-
if (retry) {
|
|
816
|
-
retry();
|
|
817
|
-
retry = undefined;
|
|
818
|
-
}
|
|
819
|
-
else
|
|
820
|
-
refresh();
|
|
821
|
-
};
|
|
822
|
-
if (value instanceof Promise) {
|
|
823
|
-
value.then(set);
|
|
824
|
-
value = undefined;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function ref(arg) {
|
|
743
|
+
return apply(function ref(key) {
|
|
744
|
+
let value = {};
|
|
745
|
+
if (typeof arg == "object") {
|
|
746
|
+
const source = control(arg);
|
|
747
|
+
for (const key in source.state)
|
|
748
|
+
defineLazy(value, key, createRef.bind(source, key));
|
|
825
749
|
}
|
|
750
|
+
else
|
|
751
|
+
value = createRef.call(this, key, arg);
|
|
752
|
+
return { value, explicit: true };
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
function createRef(key, cb) {
|
|
756
|
+
const refObjectFunction = this.ref(key, cb && createValueEffect(cb));
|
|
757
|
+
defineProperty(refObjectFunction, "current", {
|
|
758
|
+
set: refObjectFunction,
|
|
759
|
+
get: () => this.state[key]
|
|
760
|
+
});
|
|
761
|
+
return refObjectFunction;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
const Oops$7 = issues({
|
|
765
|
+
NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
|
|
766
|
+
BadFactory: () => `Set instruction can only accept a factory or undefined.`,
|
|
767
|
+
FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
|
|
768
|
+
});
|
|
769
|
+
function set(factory, argument) {
|
|
770
|
+
return apply(function set(key) {
|
|
771
|
+
let set;
|
|
772
|
+
let get;
|
|
773
|
+
const required = argument === true || argument === undefined;
|
|
774
|
+
if (factory === undefined)
|
|
775
|
+
get = () => pendingValue(this, key);
|
|
776
|
+
else if (typeof factory !== "function")
|
|
777
|
+
throw Oops$7.BadFactory();
|
|
826
778
|
else {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
779
|
+
get = pendingFactory(this, key, factory);
|
|
780
|
+
if (required)
|
|
781
|
+
try {
|
|
782
|
+
get();
|
|
783
|
+
}
|
|
784
|
+
catch (err) {
|
|
785
|
+
if (err instanceof Promise)
|
|
786
|
+
;
|
|
787
|
+
else {
|
|
788
|
+
Oops$7.FactoryFailed(this.subject, key).warn();
|
|
789
|
+
throw err;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
if (typeof argument == "function")
|
|
794
|
+
set = createValueEffect(argument);
|
|
795
|
+
else
|
|
796
|
+
set = (value) => {
|
|
797
|
+
if (value === undefined && required)
|
|
798
|
+
throw Oops$7.NonOptional(this.subject, key);
|
|
832
799
|
};
|
|
800
|
+
return { set, get };
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
const Parent = new WeakMap();
|
|
805
|
+
const Oops$6 = issues({
|
|
806
|
+
ParentRequired: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
807
|
+
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
808
|
+
});
|
|
809
|
+
function parent(Expects, required) {
|
|
810
|
+
return apply(function parent() {
|
|
811
|
+
const child = this.subject;
|
|
812
|
+
const value = Parent.get(child);
|
|
813
|
+
const expected = Expects.name;
|
|
814
|
+
if (!value) {
|
|
815
|
+
if (required !== false)
|
|
816
|
+
throw Oops$6.ParentRequired(expected, child);
|
|
833
817
|
}
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
throw new Promise(res => retry = res);
|
|
838
|
-
return value;
|
|
839
|
-
}
|
|
840
|
-
: () => value;
|
|
841
|
-
defineProperty(sub, "proxy", { get });
|
|
842
|
-
return sub;
|
|
818
|
+
else if (!(value instanceof Expects))
|
|
819
|
+
throw Oops$6.UnexpectedParent(expected, child, value);
|
|
820
|
+
return { value };
|
|
843
821
|
});
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
const
|
|
852
|
-
const
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
const Oops$5 = issues({
|
|
825
|
+
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
826
|
+
});
|
|
827
|
+
function use$1(input, argument) {
|
|
828
|
+
return apply(function use(key) {
|
|
829
|
+
const { subject } = this;
|
|
830
|
+
const onUpdate = (next) => {
|
|
831
|
+
this.state[key] = next;
|
|
832
|
+
if (next) {
|
|
833
|
+
Parent.set(next, subject);
|
|
834
|
+
control(next);
|
|
835
|
+
}
|
|
836
|
+
if (typeof argument == "function")
|
|
837
|
+
argument(next);
|
|
838
|
+
return true;
|
|
839
|
+
};
|
|
840
|
+
if (input) {
|
|
841
|
+
const value = Model.isTypeof(input)
|
|
842
|
+
? new input() :
|
|
843
|
+
typeof input === "object"
|
|
844
|
+
? input :
|
|
845
|
+
typeof input === "function"
|
|
846
|
+
? input()
|
|
847
|
+
: null;
|
|
848
|
+
if (value === null)
|
|
849
|
+
throw Oops$5.BadArgument(typeof input);
|
|
850
|
+
if (value)
|
|
851
|
+
onUpdate(value);
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
set: onUpdate,
|
|
855
|
+
recursive: true
|
|
856
|
+
};
|
|
862
857
|
});
|
|
863
|
-
return hook.proxy;
|
|
864
858
|
}
|
|
865
859
|
|
|
866
860
|
class Lookup {
|
|
@@ -868,7 +862,9 @@ class Lookup {
|
|
|
868
862
|
this.table = new Map();
|
|
869
863
|
}
|
|
870
864
|
get local() {
|
|
871
|
-
return
|
|
865
|
+
return [
|
|
866
|
+
...new Set(getOwnPropertySymbols(this).map(symbol => this[symbol]))
|
|
867
|
+
];
|
|
872
868
|
}
|
|
873
869
|
key(T) {
|
|
874
870
|
let key = this.table.get(T);
|
|
@@ -902,8 +898,12 @@ class Lookup {
|
|
|
902
898
|
I = I.create();
|
|
903
899
|
}
|
|
904
900
|
do {
|
|
905
|
-
|
|
906
|
-
|
|
901
|
+
const key = this.key(T);
|
|
902
|
+
const conflict = this.hasOwnProperty(key);
|
|
903
|
+
defineProperty(this, key, {
|
|
904
|
+
value: conflict ? null : I,
|
|
905
|
+
configurable: true,
|
|
906
|
+
writable
|
|
907
907
|
});
|
|
908
908
|
T = getPrototypeOf(T);
|
|
909
909
|
} while (T !== Model);
|
|
@@ -912,352 +912,306 @@ class Lookup {
|
|
|
912
912
|
pop() {
|
|
913
913
|
for (const key of getOwnPropertySymbols(this)) {
|
|
914
914
|
const entry = getOwnPropertyDescriptor(this, key);
|
|
915
|
-
if (entry.writable)
|
|
915
|
+
if (entry.writable && entry.value)
|
|
916
916
|
entry.value.destroy();
|
|
917
917
|
}
|
|
918
918
|
}
|
|
919
919
|
}
|
|
920
920
|
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
921
|
+
const LookupContext = React__default["default"].createContext(new Lookup());
|
|
922
|
+
const useLookup = () => React__default["default"].useContext(LookupContext);
|
|
923
|
+
const Oops$4 = issues({
|
|
924
|
+
NothingInContext: (name) => `Couldn't find ${name} in context; did you forget to use a Provider?`
|
|
925
925
|
});
|
|
926
|
-
|
|
927
|
-
const useLookup = () => react.useContext(LookupContext);
|
|
928
|
-
function useFromContext(Type, strict) {
|
|
926
|
+
function useInContext(Type, arg) {
|
|
929
927
|
const instance = useLookup().get(Type);
|
|
930
|
-
if (!instance &&
|
|
931
|
-
throw Oops$
|
|
932
|
-
return
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
const { get, has, children, of: Control } = props;
|
|
936
|
-
if (typeof children == "function")
|
|
937
|
-
return children(Control.tap());
|
|
938
|
-
const callback = has || get;
|
|
939
|
-
if (typeof callback == "function")
|
|
940
|
-
callback(Control.get(!!has));
|
|
941
|
-
else
|
|
942
|
-
throw Oops$3.BadConsumerProps();
|
|
943
|
-
return null;
|
|
944
|
-
}
|
|
945
|
-
function useNewContext(from, inject) {
|
|
946
|
-
return react.useMemo(() => {
|
|
947
|
-
if (!inject)
|
|
948
|
-
throw Oops$3.NoProviderType();
|
|
949
|
-
const context = from.push(inject);
|
|
950
|
-
for (const instance of context.local)
|
|
951
|
-
for (const apply of getPending(instance))
|
|
952
|
-
apply(context);
|
|
953
|
-
return context;
|
|
954
|
-
}, []);
|
|
955
|
-
}
|
|
956
|
-
function useAppliedProps(within, props) {
|
|
957
|
-
const update = react.useMemo(() => {
|
|
958
|
-
const targets = within.local;
|
|
959
|
-
return function integrate(props) {
|
|
960
|
-
for (const [key, value] of entries(props))
|
|
961
|
-
if (key != "of" && key != "children")
|
|
962
|
-
for (const into of targets)
|
|
963
|
-
if (key in into)
|
|
964
|
-
into[key] = value;
|
|
965
|
-
};
|
|
966
|
-
}, []);
|
|
967
|
-
update(props);
|
|
968
|
-
}
|
|
969
|
-
function RenderFunction(props) {
|
|
970
|
-
const hook = use$1(refresh => {
|
|
971
|
-
const targets = props.context.local;
|
|
972
|
-
if (targets.length == 1)
|
|
973
|
-
return new Subscriber(targets[0], () => refresh);
|
|
974
|
-
return {};
|
|
975
|
-
});
|
|
976
|
-
if (hook.commit)
|
|
977
|
-
react.useLayoutEffect(() => hook.commit(), []);
|
|
978
|
-
return props.render(hook.proxy);
|
|
979
|
-
}
|
|
980
|
-
function Provider(props) {
|
|
981
|
-
const render = props.children;
|
|
982
|
-
const current = useLookup();
|
|
983
|
-
const context = useNewContext(current, props.of);
|
|
984
|
-
useAppliedProps(context, props);
|
|
985
|
-
react.useLayoutEffect(() => () => context.pop(), []);
|
|
986
|
-
return react.createElement(LookupContext.Provider, { value: context }, typeof render == "function"
|
|
987
|
-
? react.createElement(RenderFunction, { context, render })
|
|
988
|
-
: render);
|
|
928
|
+
if (!instance && arg !== false)
|
|
929
|
+
throw Oops$4.NothingInContext(Type.name);
|
|
930
|
+
return typeof arg == "string" ?
|
|
931
|
+
instance[arg] :
|
|
932
|
+
instance;
|
|
989
933
|
}
|
|
990
934
|
|
|
991
|
-
const Oops$
|
|
992
|
-
|
|
993
|
-
|
|
935
|
+
const Oops$3 = issues({
|
|
936
|
+
CantAttachGlobal: (parent, child) => `Global '${parent}' attempted to attach '${child}' but it is not also a singleton.`,
|
|
937
|
+
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.`
|
|
994
938
|
});
|
|
995
|
-
const
|
|
996
|
-
const
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
939
|
+
const PendingContext = new WeakMap();
|
|
940
|
+
const ContextWasUsed = new WeakMap();
|
|
941
|
+
function tap(type, argument) {
|
|
942
|
+
return apply(function tap(key) {
|
|
943
|
+
if ("set" in type)
|
|
944
|
+
this.state[key] = type.get();
|
|
945
|
+
else {
|
|
946
|
+
const { subject } = this;
|
|
947
|
+
if ("set" in subject.constructor)
|
|
948
|
+
throw Oops$3.CantAttachGlobal(subject, type.name);
|
|
949
|
+
getPending(subject).push(context => {
|
|
950
|
+
let instance = context.get(type);
|
|
951
|
+
if (typeof argument == "function") {
|
|
952
|
+
if (argument(instance) === false)
|
|
953
|
+
instance = undefined;
|
|
954
|
+
}
|
|
955
|
+
else if (!instance && argument)
|
|
956
|
+
throw Oops$3.AmbientRequired(type.name, subject, key);
|
|
957
|
+
this.update(key, instance);
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
return {
|
|
961
|
+
recursive: true
|
|
962
|
+
};
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
function usePeerContext(subject) {
|
|
966
|
+
if (ContextWasUsed.has(subject)) {
|
|
967
|
+
if (ContextWasUsed.get(subject))
|
|
968
|
+
useLookup();
|
|
969
|
+
return;
|
|
1020
970
|
}
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
useComponentLifecycle(hook);
|
|
1028
|
-
return hook.proxy;
|
|
971
|
+
const pending = PendingContext.get(subject);
|
|
972
|
+
if (pending) {
|
|
973
|
+
const local = useLookup();
|
|
974
|
+
for (const init of pending)
|
|
975
|
+
init(local);
|
|
976
|
+
PendingContext.delete(subject);
|
|
1029
977
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
978
|
+
ContextWasUsed.set(subject, !!pending);
|
|
979
|
+
}
|
|
980
|
+
function getPending(subject) {
|
|
981
|
+
let pending = PendingContext.get(subject);
|
|
982
|
+
if (!pending)
|
|
983
|
+
PendingContext.set(subject, pending = []);
|
|
984
|
+
return pending;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
function use(init) {
|
|
988
|
+
const [state, update] = React__default["default"].useState(() => [
|
|
989
|
+
init(() => update(state.concat()))
|
|
990
|
+
]);
|
|
991
|
+
return state[0];
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
function useModel(source, arg, callback) {
|
|
995
|
+
const instance = React__default["default"].useMemo(() => {
|
|
996
|
+
const cb = callback || arg;
|
|
997
|
+
const instance = typeof source == "function" ?
|
|
998
|
+
source.prototype instanceof Model ?
|
|
999
|
+
new source() :
|
|
1000
|
+
source() :
|
|
1001
|
+
source;
|
|
1002
|
+
control(instance);
|
|
1003
|
+
if (typeof cb == "function")
|
|
1004
|
+
cb(instance);
|
|
1005
|
+
return instance;
|
|
1006
|
+
}, []);
|
|
1007
|
+
if (Array.isArray(arg)) {
|
|
1008
|
+
const update = React.useState(0)[1];
|
|
1009
|
+
React__default["default"].useLayoutEffect(() => {
|
|
1010
|
+
if (arg.length && instance instanceof Model)
|
|
1011
|
+
instance.on(arg, () => update(x => x + 1), true);
|
|
1012
|
+
return () => {
|
|
1013
|
+
if (Model.isTypeof(source))
|
|
1014
|
+
instance.destroy();
|
|
1015
|
+
};
|
|
1016
|
+
}, []);
|
|
1017
|
+
return instance;
|
|
1047
1018
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
return
|
|
1051
|
-
return new Promise(resolve => {
|
|
1052
|
-
this.on(select, resolve, true, true);
|
|
1019
|
+
else {
|
|
1020
|
+
const local = use(refresh => {
|
|
1021
|
+
return new Subscriber(instance, () => refresh);
|
|
1053
1022
|
});
|
|
1023
|
+
React__default["default"].useLayoutEffect(() => {
|
|
1024
|
+
local.commit();
|
|
1025
|
+
return () => {
|
|
1026
|
+
local.release();
|
|
1027
|
+
if (Model.isTypeof(source))
|
|
1028
|
+
instance.destroy();
|
|
1029
|
+
};
|
|
1030
|
+
}, []);
|
|
1031
|
+
return local.proxy;
|
|
1054
1032
|
}
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function useFrom(target, compute, suspend) {
|
|
1036
|
+
const local = use(refresh => {
|
|
1037
|
+
const sub = new Subscriber(target, () => update);
|
|
1038
|
+
const spy = sub.proxy;
|
|
1039
|
+
let value = compute.call(spy, spy);
|
|
1040
|
+
let update;
|
|
1041
|
+
let retry;
|
|
1042
|
+
const set = (next) => {
|
|
1043
|
+
value = next;
|
|
1044
|
+
if (retry) {
|
|
1045
|
+
retry();
|
|
1046
|
+
retry = undefined;
|
|
1047
|
+
}
|
|
1048
|
+
else
|
|
1049
|
+
refresh();
|
|
1050
|
+
};
|
|
1051
|
+
if (value instanceof Promise) {
|
|
1052
|
+
value.then(set);
|
|
1053
|
+
value = undefined;
|
|
1063
1054
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
if (key in from)
|
|
1072
|
-
this[key] = from[key];
|
|
1073
|
-
}
|
|
1074
|
-
export(subset) {
|
|
1075
|
-
const control = manage(this);
|
|
1076
|
-
const output = {};
|
|
1077
|
-
for (const key of keys(control, subset))
|
|
1078
|
-
output[key] = control.state[key];
|
|
1079
|
-
return output;
|
|
1080
|
-
}
|
|
1081
|
-
update(arg, tag) {
|
|
1082
|
-
const control = manage(this);
|
|
1083
|
-
if (typeof arg == "function")
|
|
1084
|
-
arg = select(this, arg);
|
|
1085
|
-
if (typeof arg == "boolean") {
|
|
1086
|
-
if (!control.pending === arg)
|
|
1087
|
-
return Promise.reject(Oops$2.StrictUpdate(arg));
|
|
1055
|
+
else {
|
|
1056
|
+
sub.commit();
|
|
1057
|
+
update = () => {
|
|
1058
|
+
const next = compute.call(spy, spy);
|
|
1059
|
+
if (value != next)
|
|
1060
|
+
set(next);
|
|
1061
|
+
};
|
|
1088
1062
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
if (typeof tag != "boolean")
|
|
1095
|
-
method.call(this, tag);
|
|
1096
|
-
else if (tag)
|
|
1097
|
-
method.call(this);
|
|
1063
|
+
defineProperty(sub, "proxy", {
|
|
1064
|
+
get() {
|
|
1065
|
+
if (value === undefined && suspend)
|
|
1066
|
+
throw new Promise(res => retry = res);
|
|
1067
|
+
return value;
|
|
1098
1068
|
}
|
|
1069
|
+
});
|
|
1070
|
+
return sub;
|
|
1071
|
+
});
|
|
1072
|
+
React__default["default"].useLayoutEffect(() => local.release, []);
|
|
1073
|
+
return local.proxy;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
function useTap(source, path, expect) {
|
|
1077
|
+
const instance = React.useMemo(() => {
|
|
1078
|
+
if (typeof source == "object")
|
|
1079
|
+
return () => source;
|
|
1080
|
+
if ("get" in source)
|
|
1081
|
+
return () => source.get();
|
|
1082
|
+
if ("prototype" in source)
|
|
1083
|
+
return () => useInContext(source);
|
|
1084
|
+
else
|
|
1085
|
+
return source;
|
|
1086
|
+
}, [])();
|
|
1087
|
+
if (typeof path == "function")
|
|
1088
|
+
return useFrom(instance, path, expect);
|
|
1089
|
+
const local = use(refresh => {
|
|
1090
|
+
const parent = control(instance);
|
|
1091
|
+
const sub = new Subscriber(parent, () => refresh);
|
|
1092
|
+
if (typeof path == "string") {
|
|
1093
|
+
const source = sub.proxy;
|
|
1094
|
+
defineProperty(sub, "proxy", {
|
|
1095
|
+
get() {
|
|
1096
|
+
const value = source[path];
|
|
1097
|
+
if (value === undefined && expect)
|
|
1098
|
+
throw suspend(parent, path);
|
|
1099
|
+
return value;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1099
1102
|
}
|
|
1100
|
-
return
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
}
|
|
1110
|
-
};
|
|
1111
|
-
}
|
|
1112
|
-
destroy() {
|
|
1113
|
-
this.update("willDestroy", true);
|
|
1114
|
-
}
|
|
1115
|
-
toString() {
|
|
1116
|
-
return this.constructor.name;
|
|
1117
|
-
}
|
|
1118
|
-
static create(...args) {
|
|
1119
|
-
const instance = new this(...args);
|
|
1120
|
-
manage(instance);
|
|
1121
|
-
return instance;
|
|
1122
|
-
}
|
|
1123
|
-
static new(callback) {
|
|
1124
|
-
const instance = useLazy(this, callback);
|
|
1125
|
-
instance.update("willRender", true);
|
|
1126
|
-
return instance;
|
|
1103
|
+
return sub;
|
|
1104
|
+
});
|
|
1105
|
+
React__default["default"].useLayoutEffect(() => local.commit(), []);
|
|
1106
|
+
return local.proxy;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
class MVC extends Model {
|
|
1110
|
+
tap(path, expect) {
|
|
1111
|
+
return useTap(this, path, expect);
|
|
1127
1112
|
}
|
|
1128
|
-
|
|
1129
|
-
return
|
|
1113
|
+
use(arg, callback) {
|
|
1114
|
+
return useModel(this, arg, callback);
|
|
1130
1115
|
}
|
|
1131
|
-
static get(
|
|
1132
|
-
|
|
1133
|
-
return (typeof key == "function" ?
|
|
1134
|
-
key(instance) :
|
|
1135
|
-
typeof key == "string" ?
|
|
1136
|
-
instance[key] :
|
|
1137
|
-
instance);
|
|
1116
|
+
static get(required) {
|
|
1117
|
+
return useInContext(this, required);
|
|
1138
1118
|
}
|
|
1139
1119
|
static tap(key, expect) {
|
|
1140
|
-
return this
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
|
|
1120
|
+
return useTap(this, key, expect);
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* **React Hook** - Spawn and maintain a controller from within a component.
|
|
1124
|
+
*
|
|
1125
|
+
* More efficient than `use()` if you don't need hook-based features.
|
|
1126
|
+
*
|
|
1127
|
+
* @param callback - Run after creation of instance.
|
|
1128
|
+
*/
|
|
1129
|
+
static new(callback) {
|
|
1130
|
+
return useModel(this, [], callback);
|
|
1144
1131
|
}
|
|
1145
|
-
static use(callback) {
|
|
1146
|
-
const instance = useModel(this, callback);
|
|
1147
|
-
useComponentLifecycle(instance[LOCAL]);
|
|
1132
|
+
static use(arg, callback) {
|
|
1133
|
+
const instance = useModel(this, arg, callback);
|
|
1148
1134
|
usePeerContext(instance.get);
|
|
1149
1135
|
return instance;
|
|
1150
1136
|
}
|
|
1151
|
-
static uses(
|
|
1137
|
+
static uses(data, only) {
|
|
1152
1138
|
return this.use(instance => {
|
|
1153
|
-
instance.import(
|
|
1139
|
+
instance.import(data, only);
|
|
1154
1140
|
});
|
|
1155
1141
|
}
|
|
1156
|
-
static using(
|
|
1142
|
+
static using(data, only) {
|
|
1157
1143
|
const instance = this.use();
|
|
1158
|
-
instance.import(
|
|
1144
|
+
instance.import(data, only);
|
|
1159
1145
|
return instance;
|
|
1160
1146
|
}
|
|
1161
|
-
static meta(path) {
|
|
1162
|
-
return
|
|
1163
|
-
? useComputed(this, path)
|
|
1164
|
-
: useWatcher(this, path);
|
|
1147
|
+
static meta(path, expect) {
|
|
1148
|
+
return useTap(() => this, path, expect);
|
|
1165
1149
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
}
|
|
1171
|
-
Model.CONTROL = CONTROL;
|
|
1172
|
-
Model.STATE = STATE;
|
|
1173
|
-
Model.LOCAL = LOCAL;
|
|
1174
|
-
Model.WHY = UPDATE;
|
|
1175
|
-
defineLazy(Model, CONTROL, function () {
|
|
1176
|
-
return new Controller(this).start();
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
const Oops$2 = issues({
|
|
1153
|
+
BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
1177
1154
|
});
|
|
1178
|
-
function
|
|
1179
|
-
const {
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1155
|
+
function Consumer(props) {
|
|
1156
|
+
const { get, has, children, of: Control } = props;
|
|
1157
|
+
if (typeof children == "function")
|
|
1158
|
+
return children(useTap(Control));
|
|
1159
|
+
const callback = has || get;
|
|
1160
|
+
if (typeof callback == "function")
|
|
1161
|
+
callback(useInContext(Control, !!has));
|
|
1162
|
+
else
|
|
1163
|
+
throw Oops$2.BadConsumerProps();
|
|
1164
|
+
return null;
|
|
1188
1165
|
}
|
|
1189
1166
|
|
|
1190
|
-
const Parent = new WeakMap();
|
|
1191
1167
|
const Oops$1 = issues({
|
|
1192
|
-
|
|
1193
|
-
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
1194
|
-
UndefinedNotAllowed: (key) => `Child property ${key} may not be undefined.`,
|
|
1195
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
1196
|
-
IsReadOnly: (owner, key) => `${owner}.${key} is set to read-only, but tried to reassign assign.`,
|
|
1197
|
-
MustBeDefined: (owner, key) => `${owner}.${key} must have initial value, as a read-only property.`
|
|
1168
|
+
NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`
|
|
1198
1169
|
});
|
|
1199
|
-
function
|
|
1200
|
-
const
|
|
1201
|
-
const
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
return
|
|
1170
|
+
function Provider(props) {
|
|
1171
|
+
const context = useNewContext(props.of);
|
|
1172
|
+
const render = props.children;
|
|
1173
|
+
useAppliedProps(context, props);
|
|
1174
|
+
React__default["default"].useLayoutEffect(() => () => context.pop(), []);
|
|
1175
|
+
return React__default["default"].createElement(LookupContext.Provider, { value: context }, typeof render == "function"
|
|
1176
|
+
? React__default["default"].createElement(RenderFunction, { context, render })
|
|
1177
|
+
: render);
|
|
1205
1178
|
}
|
|
1206
|
-
function
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
return argument(current);
|
|
1179
|
+
function useNewContext(inject) {
|
|
1180
|
+
const from = useLookup();
|
|
1181
|
+
return React__default["default"].useMemo(() => {
|
|
1182
|
+
if (!inject)
|
|
1183
|
+
throw Oops$1.NoProviderType();
|
|
1184
|
+
const context = from.push(inject);
|
|
1185
|
+
for (const instance of context.local)
|
|
1186
|
+
if (instance)
|
|
1187
|
+
for (const apply of getPending(instance))
|
|
1188
|
+
apply(context);
|
|
1189
|
+
return context;
|
|
1190
|
+
}, []);
|
|
1191
|
+
}
|
|
1192
|
+
function useAppliedProps(within, props) {
|
|
1193
|
+
const update = React__default["default"].useMemo(() => {
|
|
1194
|
+
const targets = within.local;
|
|
1195
|
+
return function integrate(props) {
|
|
1196
|
+
for (const [key, value] of entries(props))
|
|
1197
|
+
if (key != "of" && key != "children")
|
|
1198
|
+
for (const into of targets)
|
|
1199
|
+
if (into && key in into)
|
|
1200
|
+
into[key] = value;
|
|
1229
1201
|
};
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
Model.isTypeof(input) ? new input() :
|
|
1233
|
-
input instanceof Model ? input :
|
|
1234
|
-
typeof input === "function" ? input() :
|
|
1235
|
-
typeof input === "object" ? bootstrap(input) :
|
|
1236
|
-
Oops$1.BadArgument(typeof input).throw();
|
|
1237
|
-
if (current)
|
|
1238
|
-
mode = onUpdate(current, true) || mode;
|
|
1239
|
-
else if (mode == true)
|
|
1240
|
-
throw Oops$1.MustBeDefined(subject, key);
|
|
1241
|
-
}
|
|
1242
|
-
else
|
|
1243
|
-
mode = false;
|
|
1244
|
-
this.manage(key, current, onUpdate);
|
|
1245
|
-
return () => current;
|
|
1246
|
-
});
|
|
1202
|
+
}, []);
|
|
1203
|
+
update(props);
|
|
1247
1204
|
}
|
|
1248
|
-
function
|
|
1249
|
-
|
|
1250
|
-
const
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
if (required)
|
|
1255
|
-
throw Oops$1.ParentRequired(expected, child);
|
|
1256
|
-
}
|
|
1257
|
-
else if (!(value instanceof Expects))
|
|
1258
|
-
throw Oops$1.UnexpectedParent(expected, child, value);
|
|
1259
|
-
return { value };
|
|
1205
|
+
function RenderFunction(props) {
|
|
1206
|
+
const hook = use(refresh => {
|
|
1207
|
+
const targets = props.context.local;
|
|
1208
|
+
if (targets.length == 1)
|
|
1209
|
+
return new Subscriber(targets[0], () => refresh);
|
|
1210
|
+
return {};
|
|
1260
1211
|
});
|
|
1212
|
+
if (hook.commit)
|
|
1213
|
+
React__default["default"].useLayoutEffect(() => hook.commit(), []);
|
|
1214
|
+
return props.render(hook.proxy);
|
|
1261
1215
|
}
|
|
1262
1216
|
|
|
1263
1217
|
const Oops = issues({
|
|
@@ -1265,35 +1219,38 @@ const Oops = issues({
|
|
|
1265
1219
|
GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
1266
1220
|
});
|
|
1267
1221
|
const Active = new WeakMap();
|
|
1268
|
-
class
|
|
1269
|
-
static get current() {
|
|
1270
|
-
return Active.get(this);
|
|
1271
|
-
}
|
|
1222
|
+
class Global extends MVC {
|
|
1272
1223
|
static create(...args) {
|
|
1273
1224
|
const Type = this;
|
|
1274
1225
|
if (Active.has(Type))
|
|
1275
1226
|
throw Oops.GlobalExists(this.name);
|
|
1276
|
-
|
|
1227
|
+
const instance = super.create(...args);
|
|
1277
1228
|
Active.set(Type, instance);
|
|
1278
1229
|
return instance;
|
|
1279
1230
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1231
|
+
/**
|
|
1232
|
+
* Update the active instance of this class.
|
|
1233
|
+
* Returns a thenable; resolves after successful update.
|
|
1234
|
+
* If instance does not already exist, one will be created.
|
|
1235
|
+
*/
|
|
1236
|
+
static set(updates) {
|
|
1237
|
+
const instance = Active.get(this) || this.create();
|
|
1282
1238
|
instance.import(updates);
|
|
1283
1239
|
return instance.update();
|
|
1284
1240
|
}
|
|
1285
|
-
static
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
static find(strict) {
|
|
1289
|
-
const instance = this.current;
|
|
1290
|
-
if (!instance && strict)
|
|
1241
|
+
static get(arg) {
|
|
1242
|
+
const instance = Active.get(this);
|
|
1243
|
+
if (!instance && arg !== false)
|
|
1291
1244
|
throw Oops.GlobalDoesNotExist(this.name);
|
|
1292
|
-
return
|
|
1245
|
+
return (typeof arg == "string" ?
|
|
1246
|
+
instance[arg] :
|
|
1247
|
+
instance);
|
|
1293
1248
|
}
|
|
1249
|
+
/** Destroy current instance of Global, if it exists. */
|
|
1294
1250
|
static reset() {
|
|
1295
|
-
|
|
1296
|
-
|
|
1251
|
+
const current = Active.get(this);
|
|
1252
|
+
if (current)
|
|
1253
|
+
current.destroy();
|
|
1297
1254
|
}
|
|
1298
1255
|
destroy() {
|
|
1299
1256
|
super.destroy();
|
|
@@ -1301,22 +1258,25 @@ class Singleton extends Model {
|
|
|
1301
1258
|
}
|
|
1302
1259
|
}
|
|
1303
1260
|
|
|
1261
|
+
exports.CONTROL = CONTROL;
|
|
1304
1262
|
exports.Consumer = Consumer;
|
|
1305
|
-
exports.
|
|
1263
|
+
exports.Global = Global;
|
|
1264
|
+
exports.LOCAL = LOCAL;
|
|
1265
|
+
exports.Model = MVC;
|
|
1306
1266
|
exports.Provider = Provider;
|
|
1307
|
-
exports.
|
|
1267
|
+
exports.STATE = STATE;
|
|
1268
|
+
exports.WHY = WHY;
|
|
1308
1269
|
exports.act = act;
|
|
1309
1270
|
exports.apply = apply;
|
|
1310
|
-
exports
|
|
1311
|
-
exports["default"] = Model;
|
|
1271
|
+
exports["default"] = MVC;
|
|
1312
1272
|
exports.from = from;
|
|
1313
|
-
exports.lazy = lazy;
|
|
1314
|
-
exports.memo = set;
|
|
1315
|
-
exports.on = on;
|
|
1316
1273
|
exports.parent = parent;
|
|
1317
|
-
exports.pending = pending;
|
|
1318
1274
|
exports.ref = ref;
|
|
1319
1275
|
exports.set = set;
|
|
1320
1276
|
exports.tap = tap;
|
|
1321
|
-
exports.use = use;
|
|
1277
|
+
exports.use = use$1;
|
|
1278
|
+
exports.useFrom = useFrom;
|
|
1279
|
+
exports.useInContext = useInContext;
|
|
1280
|
+
exports.useModel = useModel;
|
|
1281
|
+
exports.useTap = useTap;
|
|
1322
1282
|
//# sourceMappingURL=index.js.map
|