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