@expressive/mvc 1.0.0-beta.4 → 1.0.0-beta.40
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 +592 -0
- package/lib/index.esm.js +1267 -0
- package/lib/index.esm.js.map +1 -0
- package/lib/index.js +1117 -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
|
+
});
|
|
487
|
+
}
|
|
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];
|
|
389
496
|
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
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();
|
|
471
862
|
}
|
|
472
|
-
|
|
473
|
-
return
|
|
863
|
+
get local() {
|
|
864
|
+
return [
|
|
865
|
+
...new Set(getOwnPropertySymbols(this).map(symbol => this[symbol]))
|
|
866
|
+
];
|
|
867
|
+
}
|
|
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,321 @@ 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
|
-
|
|
730
|
-
|
|
1131
|
+
/**
|
|
1132
|
+
* **React Hook** - Spawn and maintain a controller from within a component.
|
|
1133
|
+
*
|
|
1134
|
+
* More efficient than `use()` if you don't need hook-based features.
|
|
1135
|
+
*
|
|
1136
|
+
* @param callback - Run after creation of instance.
|
|
1137
|
+
*/
|
|
1138
|
+
static new(callback) {
|
|
1139
|
+
return useModel(this, [], callback);
|
|
731
1140
|
}
|
|
732
|
-
static
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
static get inherits() {
|
|
737
|
-
const I = getPrototypeOf(this);
|
|
738
|
-
if (I !== Model)
|
|
739
|
-
return I;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
defineLazy(Model, CONTROL, function () {
|
|
743
|
-
const dispatch = new Controller(this);
|
|
744
|
-
dispatch.start();
|
|
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);
|
|
1141
|
+
static use(a, b) {
|
|
1142
|
+
const instance = useModel(this, a, b);
|
|
1143
|
+
usePeerContext(instance.get);
|
|
1144
|
+
return instance;
|
|
769
1145
|
}
|
|
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
|
|
1146
|
+
/**
|
|
1147
|
+
* @deprecated consider doing this manually - not worth minor efficiency gain over using.
|
|
1148
|
+
*/
|
|
1149
|
+
static uses(apply, keys) {
|
|
1150
|
+
return this.use(instance => {
|
|
1151
|
+
instance.import(apply, keys);
|
|
814
1152
|
});
|
|
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
1153
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
1154
|
+
/**
|
|
1155
|
+
* @deprecated is now replaced by overload of `use` method.
|
|
1156
|
+
*/
|
|
1157
|
+
static using(apply, keys) {
|
|
1158
|
+
return this.use(apply, keys);
|
|
1159
|
+
}
|
|
1160
|
+
static meta(path, expect) {
|
|
1161
|
+
return useTap(() => this, path, expect);
|
|
876
1162
|
}
|
|
877
|
-
return {
|
|
878
|
-
queueComputed,
|
|
879
|
-
flushComputed
|
|
880
|
-
};
|
|
881
1163
|
}
|
|
882
1164
|
|
|
883
1165
|
const Oops$2 = issues({
|
|
884
|
-
|
|
885
|
-
DuplicateAction: (key) => `Invoked action ${key} but one is already active.`
|
|
1166
|
+
BadConsumerProps: () => `Provider expects either a render function, 'get' or 'has' props.`
|
|
886
1167
|
});
|
|
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
|
-
});
|
|
1168
|
+
function Consumer(props) {
|
|
1169
|
+
const { get, has, children, of: Control } = props;
|
|
1170
|
+
if (typeof children == "function")
|
|
1171
|
+
return children(useTap(Control));
|
|
1172
|
+
const callback = has || get;
|
|
1173
|
+
if (typeof callback == "function")
|
|
1174
|
+
callback(useInContext(Control, !!has));
|
|
1175
|
+
else
|
|
1176
|
+
throw Oops$2.BadConsumerProps();
|
|
1177
|
+
return null;
|
|
957
1178
|
}
|
|
958
1179
|
|
|
959
|
-
const ParentRelationship = new WeakMap();
|
|
960
1180
|
const Oops$1 = issues({
|
|
961
|
-
|
|
962
|
-
UnexpectedParent: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`
|
|
1181
|
+
NoProviderType: () => `Provider 'of' prop must be Model, typeof Model or a collection of them.`
|
|
963
1182
|
});
|
|
964
|
-
function
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
});
|
|
1183
|
+
function Provider(props) {
|
|
1184
|
+
const context = useNewContext(props.of);
|
|
1185
|
+
const render = props.children;
|
|
1186
|
+
useAppliedProps(context, props);
|
|
1187
|
+
React__default["default"].useLayoutEffect(() => () => context.pop(), []);
|
|
1188
|
+
return React__default["default"].createElement(LookupContext.Provider, { value: context }, typeof render == "function"
|
|
1189
|
+
? React__default["default"].createElement(RenderFunction, { context, render })
|
|
1190
|
+
: render);
|
|
973
1191
|
}
|
|
974
|
-
function
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1192
|
+
function useNewContext(inject) {
|
|
1193
|
+
const from = useLookup();
|
|
1194
|
+
return React__default["default"].useMemo(() => {
|
|
1195
|
+
if (!inject)
|
|
1196
|
+
throw Oops$1.NoProviderType();
|
|
1197
|
+
const context = from.push(inject);
|
|
1198
|
+
for (const instance of context.local)
|
|
1199
|
+
if (instance)
|
|
1200
|
+
for (const apply of getPending(instance))
|
|
1201
|
+
apply(context);
|
|
1202
|
+
return context;
|
|
1203
|
+
}, []);
|
|
1204
|
+
}
|
|
1205
|
+
function useAppliedProps(within, props) {
|
|
1206
|
+
const update = React__default["default"].useMemo(() => {
|
|
1207
|
+
const targets = within.local;
|
|
1208
|
+
return function integrate(props) {
|
|
1209
|
+
for (const [key, value] of entries(props))
|
|
1210
|
+
if (key != "of" && key != "children")
|
|
1211
|
+
for (const into of targets)
|
|
1212
|
+
if (into && key in into)
|
|
1213
|
+
into[key] = value;
|
|
1214
|
+
};
|
|
1215
|
+
}, []);
|
|
1216
|
+
update(props);
|
|
1217
|
+
}
|
|
1218
|
+
function RenderFunction(props) {
|
|
1219
|
+
const hook = use(refresh => {
|
|
1220
|
+
const targets = props.context.local;
|
|
1221
|
+
if (targets.length == 1)
|
|
1222
|
+
return new Subscriber(targets[0], () => refresh);
|
|
1223
|
+
return {};
|
|
988
1224
|
});
|
|
1225
|
+
if (hook.commit)
|
|
1226
|
+
React__default["default"].useLayoutEffect(hook.commit, []);
|
|
1227
|
+
return props.render(hook.proxy);
|
|
989
1228
|
}
|
|
990
1229
|
|
|
991
1230
|
const Oops = issues({
|
|
992
1231
|
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
1232
|
GlobalExists: (name) => `Shared instance of ${name} already exists! Consider unmounting existing, or use ${name}.reset() to force-delete it.`
|
|
994
1233
|
});
|
|
995
|
-
const
|
|
996
|
-
class
|
|
997
|
-
static get current() {
|
|
998
|
-
return Register.get(this);
|
|
999
|
-
}
|
|
1234
|
+
const Active = new WeakMap();
|
|
1235
|
+
class Global extends MVC {
|
|
1000
1236
|
static create(...args) {
|
|
1001
1237
|
const Type = this;
|
|
1002
|
-
|
|
1003
|
-
if (instance)
|
|
1238
|
+
if (Active.has(Type))
|
|
1004
1239
|
throw Oops.GlobalExists(this.name);
|
|
1005
|
-
instance = super.create(...args);
|
|
1006
|
-
|
|
1240
|
+
const instance = super.create(...args);
|
|
1241
|
+
Active.set(Type, instance);
|
|
1007
1242
|
return instance;
|
|
1008
1243
|
}
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1244
|
+
/**
|
|
1245
|
+
* Update the active instance of this class.
|
|
1246
|
+
* Returns a thenable; resolves after successful update.
|
|
1247
|
+
* If instance does not already exist, one will be created.
|
|
1248
|
+
*/
|
|
1249
|
+
static set(updates) {
|
|
1250
|
+
const instance = Active.get(this) || this.create();
|
|
1251
|
+
instance.import(updates);
|
|
1252
|
+
return instance.update();
|
|
1253
|
+
}
|
|
1254
|
+
static get(arg) {
|
|
1255
|
+
const instance = Active.get(this);
|
|
1256
|
+
if (!instance && arg !== false)
|
|
1012
1257
|
throw Oops.GlobalDoesNotExist(this.name);
|
|
1013
|
-
|
|
1014
|
-
|
|
1258
|
+
return (typeof arg == "string" ?
|
|
1259
|
+
instance[arg] :
|
|
1260
|
+
instance);
|
|
1015
1261
|
}
|
|
1262
|
+
/** Destroy current instance of Global, if it exists. */
|
|
1016
1263
|
static reset() {
|
|
1017
|
-
|
|
1018
|
-
|
|
1264
|
+
const current = Active.get(this);
|
|
1265
|
+
if (current)
|
|
1266
|
+
current.destroy();
|
|
1019
1267
|
}
|
|
1020
1268
|
destroy() {
|
|
1021
1269
|
super.destroy();
|
|
1022
|
-
|
|
1270
|
+
Active.delete(this.constructor);
|
|
1023
1271
|
}
|
|
1024
1272
|
}
|
|
1025
1273
|
|
|
1274
|
+
exports.CONTROL = CONTROL;
|
|
1026
1275
|
exports.Consumer = Consumer;
|
|
1027
|
-
exports.
|
|
1276
|
+
exports.Global = Global;
|
|
1277
|
+
exports.LOCAL = LOCAL;
|
|
1278
|
+
exports.Model = MVC;
|
|
1028
1279
|
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.
|
|
1280
|
+
exports.STATE = STATE;
|
|
1281
|
+
exports.WHY = WHY;
|
|
1282
|
+
exports.act = act;
|
|
1283
|
+
exports.apply = apply;
|
|
1284
|
+
exports["default"] = MVC;
|
|
1285
|
+
exports.from = from;
|
|
1286
|
+
exports.parent = parent;
|
|
1287
|
+
exports.ref = ref;
|
|
1288
|
+
exports.set = set;
|
|
1289
|
+
exports.tap = tap;
|
|
1290
|
+
exports.use = use$1;
|
|
1291
|
+
exports.useFrom = useFrom;
|
|
1292
|
+
exports.useInContext = useInContext;
|
|
1293
|
+
exports.useModel = useModel;
|
|
1294
|
+
exports.useTap = useTap;
|
|
1295
|
+
//# sourceMappingURL=index.js.map
|