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