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