@expressive/mvc 0.87.0 → 0.89.0
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 +19 -19
- package/dist/component.d.ts +28 -16
- package/dist/component.js +53 -72
- package/dist/component.js.map +1 -1
- package/dist/context.d.ts +28 -26
- package/dist/context.js +45 -27
- package/dist/context.js.map +1 -1
- package/dist/dispatch.d.ts +6 -1
- package/dist/dispatch.js +14 -6
- package/dist/dispatch.js.map +1 -1
- package/dist/field/def.d.ts +3 -3
- package/dist/field/def.js +7 -7
- package/dist/field/def.js.map +1 -1
- package/dist/field/get.d.ts +16 -16
- package/dist/field/get.js +21 -5
- package/dist/field/get.js.map +1 -1
- package/dist/field/has.d.ts +8 -8
- package/dist/field/has.js +3 -3
- package/dist/field/has.js.map +1 -1
- package/dist/field/map.d.ts +2 -2
- package/dist/field/map.js +2 -2
- package/dist/field/map.js.map +1 -1
- package/dist/field/ref.d.ts +8 -8
- package/dist/field/ref.js +3 -3
- package/dist/field/ref.js.map +1 -1
- package/dist/field/set.js +1 -1
- package/dist/field/set.js.map +1 -1
- package/dist/hot.d.ts +5 -8
- package/dist/hot.js +126 -18
- package/dist/hot.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +4 -5
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -2
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-runtime.d.ts +77 -4
- package/dist/jsx-runtime.js +67 -2
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/observable.d.ts +7 -4
- package/dist/observable.js +94 -27
- package/dist/observable.js.map +1 -1
- package/dist/state.d.ts +154 -112
- package/dist/state.js +115 -192
- package/dist/state.js.map +1 -1
- package/package.json +7 -5
- package/dist/_virtual/_rolldown/runtime.js +0 -18
- package/dist/caught.d.ts +0 -5237
- package/dist/caught.js +0 -64
- package/dist/caught.js.map +0 -1
- package/dist/runtime.d.ts +0 -72
- package/dist/runtime.js +0 -70
- package/dist/runtime.js.map +0 -1
package/dist/state.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { REPORT } from "./dispatch.js";
|
|
2
2
|
import { capture, event, listener, observer, queued, touch, watch } from "./observable.js";
|
|
3
|
-
import { Context, join } from "./context.js";
|
|
3
|
+
import { Context, host, join } from "./context.js";
|
|
4
4
|
|
|
5
5
|
//#region src/state.ts
|
|
6
6
|
const define = Object.defineProperty;
|
|
@@ -8,7 +8,7 @@ const define = Object.defineProperty;
|
|
|
8
8
|
const ID = /* @__PURE__ */ new WeakMap();
|
|
9
9
|
/** Internal state assigned to states. */
|
|
10
10
|
const STORE = /* @__PURE__ */ new WeakMap();
|
|
11
|
-
/**
|
|
11
|
+
/** Models under construction - added on `new`, removed when activated or released.
|
|
12
12
|
* Also carries work to run at the deadline, which `def` uses to bound its registry. */
|
|
13
13
|
const PENDING = /* @__PURE__ */ new Set();
|
|
14
14
|
const SETUP = /* @__PURE__ */ new WeakMap();
|
|
@@ -22,35 +22,31 @@ const METHODS = /* @__PURE__ */ new WeakMap();
|
|
|
22
22
|
const GETTERS = /* @__PURE__ */ new WeakMap();
|
|
23
23
|
/** Replacement for a getter captured by live computed properties, for hot patching. */
|
|
24
24
|
const LATEST = /* @__PURE__ */ new WeakMap();
|
|
25
|
-
/** Method implementations replaced by a hot patch. */
|
|
26
|
-
const PAST = /* @__PURE__ */ new WeakSet();
|
|
27
|
-
/** Live instances, tracked once hot patching is enabled. */
|
|
28
|
-
let LIVE;
|
|
29
|
-
/** Bootstrapped subclasses of each class, tracked once hot patching is enabled. */
|
|
30
|
-
const SUBCLASSES = /* @__PURE__ */ new WeakMap();
|
|
31
25
|
/** Event every observer treats as watched, forcing a refresh after a hot patch. */
|
|
32
26
|
const REFRESH = Symbol.for("@expressive/mvc.refresh");
|
|
33
27
|
/** Stale flags for compute closures awaiting refresh on next access. */
|
|
34
28
|
const STALE = /* @__PURE__ */ new WeakSet();
|
|
35
29
|
/** Whether the deadline which drains `PENDING` is already queued for this tick. */
|
|
36
30
|
let QUEUED = false;
|
|
37
|
-
/** Global list each loaded copy of this module adds its `
|
|
31
|
+
/** Global list each loaded copy of this module adds its `Model` to, on first construction. */
|
|
38
32
|
const COPIES = Symbol.for("@expressive/mvc");
|
|
39
33
|
let ANNOUNCED = false;
|
|
40
|
-
/** Adopters for managed properties which have held a child
|
|
34
|
+
/** Adopters for managed properties which have held a child Model. */
|
|
41
35
|
const ADOPT = /* @__PURE__ */ new WeakMap();
|
|
42
36
|
const CHILDREN = /* @__PURE__ */ new WeakMap();
|
|
43
|
-
|
|
37
|
+
const OWNS = /* @__PURE__ */ new WeakMap();
|
|
38
|
+
const OWNED = /* @__PURE__ */ new WeakMap();
|
|
39
|
+
var Model = class Model {
|
|
44
40
|
/**
|
|
45
41
|
* Whether an instance activated with no enclosing context registers itself
|
|
46
42
|
* to the process-global root, where `get()` can resolve it from anywhere.
|
|
47
43
|
* `false` (the default) keeps a context-less instance fully functional but
|
|
48
44
|
* private - not injectable, though it can still read declared globals. Opt in
|
|
49
|
-
* with `static readonly global = true`; a resolver (see {@link
|
|
45
|
+
* with `static readonly global = true`; a resolver (see {@link Model.Global})
|
|
50
46
|
* makes the choice conditional. It must be declared per class - a subclass
|
|
51
47
|
* that would inherit a global without its own declaration throws on
|
|
52
|
-
* activation, so an accidental global (a forgotten
|
|
53
|
-
* global) cannot leak into the shared root.
|
|
48
|
+
* activation, so an accidental global (a forgotten `<Component for>`, an
|
|
49
|
+
* extended global) cannot leak into the shared root.
|
|
54
50
|
*/
|
|
55
51
|
static global = false;
|
|
56
52
|
constructor(...args) {
|
|
@@ -60,7 +56,8 @@ var State = class State {
|
|
|
60
56
|
get(arg1, arg2, arg3) {
|
|
61
57
|
const self = this.is;
|
|
62
58
|
if (arg1 === void 0) return values(self);
|
|
63
|
-
if (
|
|
59
|
+
if (arg1 === Model) return typeof arg2 == "function" ? owned(self, arg2) : observed(this, arg1, owner(self, arg2));
|
|
60
|
+
if (Model.is(arg1)) return observed(this, arg1, Context.get(self).get(arg1, arg2, arg3, self));
|
|
64
61
|
if (typeof arg1 == "function") return watch(self, unbind(arg1));
|
|
65
62
|
if (typeof arg2 == "function") return callback(self, arg2, arg1);
|
|
66
63
|
if (arg1 === null) return observer(self) === null;
|
|
@@ -78,7 +75,7 @@ var State = class State {
|
|
|
78
75
|
return queued(self);
|
|
79
76
|
}
|
|
80
77
|
/**
|
|
81
|
-
* Iterate over managed properties in this instance of
|
|
78
|
+
* Iterate over managed properties in this instance of Model.
|
|
82
79
|
* Yeilds the key and current value for each property.
|
|
83
80
|
*/
|
|
84
81
|
[Symbol.iterator]() {
|
|
@@ -105,30 +102,23 @@ var State = class State {
|
|
|
105
102
|
static is(maybe) {
|
|
106
103
|
return maybe === this || typeof maybe == "function" && maybe.prototype instanceof this;
|
|
107
104
|
}
|
|
108
|
-
/**
|
|
109
|
-
* Register a lifecycle handler for this State and its subclasses.
|
|
110
|
-
*
|
|
111
|
-
* A bare function is per-instance setup run in the `prepare` phase (sugar for
|
|
112
|
-
* `{ before }`); if it returns a function, that runs when the instance is
|
|
113
|
-
* destroyed. Pass a {@link State.On} object to hook by cadence - `type`
|
|
114
|
-
* (per-class, at bootstrap), `before` (per-instance, before `new()`), and
|
|
115
|
-
* `after` (per-instance, at the `new()` slot).
|
|
116
|
-
*
|
|
117
|
-
* @returns Function to remove the handler.
|
|
118
|
-
*/
|
|
119
105
|
static on(handler) {
|
|
106
|
+
if (typeof handler == "function") handler = { setup: handler };
|
|
120
107
|
let setup = SETUP.get(this);
|
|
121
108
|
if (!setup) SETUP.set(this, setup = /* @__PURE__ */ new Set());
|
|
122
109
|
setup.add(handler);
|
|
123
110
|
return () => setup.delete(handler);
|
|
124
111
|
}
|
|
125
112
|
};
|
|
126
|
-
define(
|
|
113
|
+
define(Model.prototype, "toString", { value() {
|
|
127
114
|
return ID.get(this.is);
|
|
128
115
|
} });
|
|
129
|
-
define(
|
|
116
|
+
define(Model, "toString", { value() {
|
|
130
117
|
return this.name;
|
|
131
118
|
} });
|
|
119
|
+
function observed(from, key, value) {
|
|
120
|
+
return value instanceof Model ? touch(from, key, value) : value;
|
|
121
|
+
}
|
|
132
122
|
/** Register a user OnEvent callback, preserving `this` and `source`. */
|
|
133
123
|
function callback(self, cb, select) {
|
|
134
124
|
return listener(self, (key) => cb.call(self, key, self), select);
|
|
@@ -139,15 +129,14 @@ function callback(self, cb, select) {
|
|
|
139
129
|
**/
|
|
140
130
|
function init(state, ...args) {
|
|
141
131
|
const T = state.constructor;
|
|
142
|
-
if (T ===
|
|
132
|
+
if (T === Model) throw new Error("Cannot create base Model.");
|
|
143
133
|
if (!ANNOUNCED) {
|
|
144
134
|
ANNOUNCED = true;
|
|
145
|
-
(globalThis[COPIES] ||= []).push(
|
|
135
|
+
(globalThis[COPIES] ||= []).push(Model);
|
|
146
136
|
}
|
|
147
137
|
const { before, after } = bootstrap(T);
|
|
148
138
|
ID.set(state, `${T}-${uid()}`);
|
|
149
139
|
STORE.set(state, {});
|
|
150
|
-
LIVE?.add(new WeakRef(state));
|
|
151
140
|
function observe() {
|
|
152
141
|
for (const key in state) {
|
|
153
142
|
const desc = Object.getOwnPropertyDescriptor(state, key) || {};
|
|
@@ -162,13 +151,20 @@ function init(state, ...args) {
|
|
|
162
151
|
const g = type.global;
|
|
163
152
|
if (!(typeof g == "function" ? g(state) : g)) return;
|
|
164
153
|
if (!Object.prototype.hasOwnProperty.call(type, "global")) throw new Error(`${state} would register as a global by inheritance alone - re-declare \`static global\` on ${type.name} (\`true\` to keep it, \`false\` to opt out).`);
|
|
154
|
+
for (let T = type; T !== Model; T = Object.getPrototypeOf(T)) {
|
|
155
|
+
const found = Context.root.get(T, false);
|
|
156
|
+
if (found && (T === type || found.constructor === T)) throw new Error(`Cannot register ${state} as a global - ${found} already exists in root. Destroy the existing instance first, or provide additional ones via explicit context.`);
|
|
157
|
+
}
|
|
165
158
|
return Context.root.add(state);
|
|
166
159
|
}
|
|
167
160
|
listener(state, (key) => {
|
|
168
161
|
const rest = trailing(state);
|
|
169
162
|
PENDING.delete(state);
|
|
170
163
|
if (key === null) return null;
|
|
171
|
-
parent(state, null);
|
|
164
|
+
if (!PARENT.has(state)) parent(state, host(state) || null);
|
|
165
|
+
const above = PARENT.get(state);
|
|
166
|
+
const owns = above && (OWNS.get(above) || OWNS.set(above, /* @__PURE__ */ new Set()).get(above));
|
|
167
|
+
if (owns) listener(state, () => void owns.delete(state), null);
|
|
172
168
|
const queue = [
|
|
173
169
|
...before,
|
|
174
170
|
observe,
|
|
@@ -181,12 +177,16 @@ function init(state, ...args) {
|
|
|
181
177
|
for (let i = 0; i < queue.length; i++) {
|
|
182
178
|
const arg = queue[i];
|
|
183
179
|
const out = typeof arg == "function" ? arg.call(state, state) : arg;
|
|
184
|
-
if (out instanceof Promise) out.catch((err) => report(
|
|
180
|
+
if (out instanceof Promise) out.catch((err) => report("setup", state, err));
|
|
185
181
|
else if (Array.isArray(out)) queue.splice(i + 1, 0, ...out);
|
|
186
182
|
else if (typeof out == "function") listener(state, out, null);
|
|
187
183
|
else if (typeof out == "object") assign(state, out, true);
|
|
188
184
|
}
|
|
189
185
|
});
|
|
186
|
+
if (owns) {
|
|
187
|
+
owns.add(state);
|
|
188
|
+
OWNED.get(above)?.forEach((cb) => cb(state));
|
|
189
|
+
}
|
|
190
190
|
let end = rest.length;
|
|
191
191
|
while (end-- > 0 && PENDING.has(rest[end]));
|
|
192
192
|
for (let i = 0; i < end; i++) PENDING.delete(rest[i]);
|
|
@@ -197,7 +197,7 @@ function init(state, ...args) {
|
|
|
197
197
|
queueMicrotask(() => {
|
|
198
198
|
QUEUED = false;
|
|
199
199
|
for (const item of PENDING) if (typeof item == "function") item();
|
|
200
|
-
else report(new
|
|
200
|
+
else report("unused", item, /* @__PURE__ */ new Error(`${item} was constructed but never activated.`));
|
|
201
201
|
PENDING.clear();
|
|
202
202
|
});
|
|
203
203
|
}
|
|
@@ -216,7 +216,7 @@ function unmanaged(state, key, value) {
|
|
|
216
216
|
/**
|
|
217
217
|
* Apply instructions and inherited event listeners. Ensure class metadata is ready.
|
|
218
218
|
*
|
|
219
|
-
* @param T -
|
|
219
|
+
* @param T - Model class to bootstrap.
|
|
220
220
|
* @return Array of init functions to run on instance, in order of class hierarchy.
|
|
221
221
|
*/
|
|
222
222
|
function bootstrap(T) {
|
|
@@ -228,29 +228,22 @@ function bootstrap(T) {
|
|
|
228
228
|
let getters = /* @__PURE__ */ new Map();
|
|
229
229
|
while (true) {
|
|
230
230
|
chain.unshift(T);
|
|
231
|
-
if (T ===
|
|
231
|
+
if (T === Model) break;
|
|
232
232
|
T = Object.getPrototypeOf(T);
|
|
233
233
|
}
|
|
234
234
|
for (const type of chain) {
|
|
235
|
-
for (const handler of SETUP.get(type) || [])
|
|
236
|
-
|
|
237
|
-
if (handler.
|
|
238
|
-
if (handler.after) after.add(handler.after);
|
|
235
|
+
for (const handler of SETUP.get(type) || []) {
|
|
236
|
+
if (handler.setup) before.add(handler.setup);
|
|
237
|
+
if (handler.ready) after.add(handler.ready);
|
|
239
238
|
if (handler.type) onType.add(handler.type);
|
|
240
239
|
}
|
|
241
|
-
if (type ===
|
|
240
|
+
if (type === Model) continue;
|
|
242
241
|
if (METHODS.has(type)) {
|
|
243
242
|
keys = METHODS.get(type);
|
|
244
243
|
getters = GETTERS.get(type);
|
|
245
244
|
continue;
|
|
246
245
|
}
|
|
247
246
|
for (const setupType of onType) setupType(type);
|
|
248
|
-
if (LIVE) {
|
|
249
|
-
const parent = Object.getPrototypeOf(type);
|
|
250
|
-
let children = SUBCLASSES.get(parent);
|
|
251
|
-
if (!children) SUBCLASSES.set(parent, children = /* @__PURE__ */ new Set());
|
|
252
|
-
children.add(type);
|
|
253
|
-
}
|
|
254
247
|
METHODS.set(type, keys = new Map(keys));
|
|
255
248
|
GETTERS.set(type, getters = new Map(getters));
|
|
256
249
|
classify(type, keys, getters);
|
|
@@ -295,6 +288,7 @@ function classify(type, keys, getters) {
|
|
|
295
288
|
writable: true,
|
|
296
289
|
configurable: true
|
|
297
290
|
});
|
|
291
|
+
for (const handler of stages(is.constructor, "method")) handler.call(is, key, bound, is);
|
|
298
292
|
return bound;
|
|
299
293
|
}
|
|
300
294
|
UNBIND.set(bind, value);
|
|
@@ -305,6 +299,12 @@ function classify(type, keys, getters) {
|
|
|
305
299
|
});
|
|
306
300
|
}
|
|
307
301
|
}
|
|
302
|
+
/** Handlers of one stage along the class chain - ancestor first, in registration order, each once. */
|
|
303
|
+
function stages(T, key) {
|
|
304
|
+
const found = T === Model ? /* @__PURE__ */ new Set() : stages(Object.getPrototypeOf(T), key);
|
|
305
|
+
for (const handler of SETUP.get(T) || []) if (handler[key]) found.add(handler[key]);
|
|
306
|
+
return found;
|
|
307
|
+
}
|
|
308
308
|
/**
|
|
309
309
|
* Install a reactive computed property on a state instance, derived from a prototype
|
|
310
310
|
* getter or an arity-bearing `set` factory.
|
|
@@ -317,6 +317,8 @@ function compute(getter, key) {
|
|
|
317
317
|
const store = STORE.get(this);
|
|
318
318
|
let reset;
|
|
319
319
|
let isAsync;
|
|
320
|
+
let suspended = false;
|
|
321
|
+
let waiting;
|
|
320
322
|
let proxy;
|
|
321
323
|
const connect = () => {
|
|
322
324
|
reset = watch(this, (current) => {
|
|
@@ -332,15 +334,27 @@ function compute(getter, key) {
|
|
|
332
334
|
};
|
|
333
335
|
const run = (initial) => {
|
|
334
336
|
let next;
|
|
337
|
+
waiting = void 0;
|
|
335
338
|
try {
|
|
336
339
|
next = latest(getter).call(proxy, proxy);
|
|
337
340
|
} catch (err) {
|
|
338
|
-
if (
|
|
341
|
+
if (err instanceof Promise) {
|
|
342
|
+
if (initial) {
|
|
343
|
+
suspended = true;
|
|
344
|
+
throw err;
|
|
345
|
+
}
|
|
346
|
+
const retry = () => {
|
|
347
|
+
if (waiting === err && observer(this) !== null) run();
|
|
348
|
+
};
|
|
349
|
+
waiting = err;
|
|
350
|
+
err.then(retry, retry);
|
|
351
|
+
if (suspended) return;
|
|
352
|
+
} else if (initial) {
|
|
339
353
|
console.warn(`An exception was thrown while initializing ${this}.${key}.`);
|
|
340
354
|
throw err;
|
|
341
|
-
}
|
|
342
|
-
if (!(err instanceof Promise)) report(new Caught.Getter(this, key, err));
|
|
355
|
+
} else report("getter", this, err, key);
|
|
343
356
|
}
|
|
357
|
+
suspended = false;
|
|
344
358
|
update(this, key, next, !isAsync);
|
|
345
359
|
};
|
|
346
360
|
apply(this, key, {
|
|
@@ -353,7 +367,7 @@ function compute(getter, key) {
|
|
|
353
367
|
isAsync = true;
|
|
354
368
|
}
|
|
355
369
|
if (STALE.delete(run)) run();
|
|
356
|
-
return access(this, key,
|
|
370
|
+
return access(this, key, suspended);
|
|
357
371
|
}
|
|
358
372
|
}, true);
|
|
359
373
|
}
|
|
@@ -362,7 +376,7 @@ function compute(getter, key) {
|
|
|
362
376
|
* If the property already is managed, config will only accept value.
|
|
363
377
|
* If the property does not exist, it will be created and made reactive.
|
|
364
378
|
*
|
|
365
|
-
* @param state -
|
|
379
|
+
* @param state - Model to apply property to.
|
|
366
380
|
* @param key - Property to define or update.
|
|
367
381
|
* @param config - Descriptor config with value, get, set, enumerable, and/or destroy.
|
|
368
382
|
* @param silent - If an update does occur, listeners will not be refreshed automatically.
|
|
@@ -420,7 +434,7 @@ function child(state) {
|
|
|
420
434
|
listener(state, reset, null);
|
|
421
435
|
return (value) => {
|
|
422
436
|
reset();
|
|
423
|
-
if (!(value instanceof
|
|
437
|
+
if (!(value instanceof Model)) return;
|
|
424
438
|
if (parent(value, state)) {
|
|
425
439
|
const remove = join(state, value);
|
|
426
440
|
cleanup = () => {
|
|
@@ -435,18 +449,18 @@ function child(state) {
|
|
|
435
449
|
};
|
|
436
450
|
}
|
|
437
451
|
/**
|
|
438
|
-
* Pending
|
|
452
|
+
* Pending Models constructed after this one - in a parent, the products of
|
|
439
453
|
* its own initializers, until the last one it kept.
|
|
440
454
|
*/
|
|
441
455
|
function trailing(state) {
|
|
442
456
|
const rest = [];
|
|
443
457
|
let seen = false;
|
|
444
458
|
for (const item of PENDING) if (!seen) seen = item === state;
|
|
445
|
-
else if (item instanceof
|
|
459
|
+
else if (item instanceof Model) rest.push(item);
|
|
446
460
|
return rest;
|
|
447
461
|
}
|
|
448
462
|
/**
|
|
449
|
-
* Report
|
|
463
|
+
* Report Models adopted by a parent - those already held, then each one
|
|
450
464
|
* claimed later. Returns a callback to stop watching.
|
|
451
465
|
*/
|
|
452
466
|
function children(state, callback) {
|
|
@@ -454,13 +468,33 @@ function children(state, callback) {
|
|
|
454
468
|
const keys = ADOPT.get(state);
|
|
455
469
|
if (keys) for (const key of keys.keys()) {
|
|
456
470
|
const value = store[key];
|
|
457
|
-
if (value instanceof
|
|
471
|
+
if (value instanceof Model) callback(value);
|
|
458
472
|
}
|
|
459
473
|
let set = CHILDREN.get(state);
|
|
460
474
|
if (!set) CHILDREN.set(state, set = /* @__PURE__ */ new Set());
|
|
461
475
|
set.add(callback);
|
|
462
476
|
return () => set.delete(callback);
|
|
463
477
|
}
|
|
478
|
+
function owner(state, required) {
|
|
479
|
+
const found = PARENT.get(state);
|
|
480
|
+
if (found || required === false) return found || void 0;
|
|
481
|
+
throw new Error(`${state} has no owner.`);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Report Models owned by this one - those active now, then each one as it
|
|
485
|
+
* activates. A function returned by `callback` runs when that Model is destroyed.
|
|
486
|
+
*/
|
|
487
|
+
function owned(state, callback) {
|
|
488
|
+
function each(child) {
|
|
489
|
+
const done = callback(child);
|
|
490
|
+
if (typeof done == "function") listener(child, () => void done(), null);
|
|
491
|
+
}
|
|
492
|
+
OWNS.get(state)?.forEach(each);
|
|
493
|
+
let set = OWNED.get(state);
|
|
494
|
+
if (!set) OWNED.set(state, set = /* @__PURE__ */ new Set());
|
|
495
|
+
set.add(each);
|
|
496
|
+
return () => void set.delete(each);
|
|
497
|
+
}
|
|
464
498
|
/** Currently accumulating export. Stores real values of placeholder properties such as ref() or child states. */
|
|
465
499
|
let EXPORT;
|
|
466
500
|
function values(state) {
|
|
@@ -524,15 +558,16 @@ function assign(state, data, silent) {
|
|
|
524
558
|
*
|
|
525
559
|
* This is used internally to update properties, but can also be used to update properties which are not managed by state, or to update values without triggering setters.
|
|
526
560
|
*
|
|
527
|
-
* A destroyed state
|
|
561
|
+
* A destroyed state stores the write without dispatch, reports it unless `silent`, and returns `false`.
|
|
528
562
|
*/
|
|
529
563
|
function update(state, key, value, silent, own) {
|
|
564
|
+
const store = STORE.get(state);
|
|
565
|
+
if (value instanceof Model) value = value.is;
|
|
530
566
|
if (observer(state) === null) {
|
|
531
|
-
if (!silent) report(new
|
|
567
|
+
if (!silent) report("dead", state, /* @__PURE__ */ new Error(`Tried to update ${state}.${String(key)} but state is destroyed.`), String(key));
|
|
568
|
+
store[key] = value;
|
|
532
569
|
return false;
|
|
533
570
|
}
|
|
534
|
-
const store = STORE.get(state);
|
|
535
|
-
if (value instanceof State) value = value.is;
|
|
536
571
|
if (key in store && value === store[key]) return false;
|
|
537
572
|
store[key] = value;
|
|
538
573
|
if (!silent) event(state, key);
|
|
@@ -540,55 +575,38 @@ function update(state, key, value, silent, own) {
|
|
|
540
575
|
return true;
|
|
541
576
|
}
|
|
542
577
|
/**
|
|
543
|
-
* Pass
|
|
544
|
-
* first - until one returns nothing. Passed off
|
|
545
|
-
*
|
|
546
|
-
*
|
|
578
|
+
* Pass an error along `catch` handlers - most-derived class first, last registered
|
|
579
|
+
* first, one on several classes once at the outermost - until one returns nothing. Passed off
|
|
580
|
+
* the end, a destroyed write outputs nothing, `unused` warns, anything else escapes uncaught;
|
|
581
|
+
* so does a handler's throw.
|
|
547
582
|
*/
|
|
548
|
-
function report(
|
|
549
|
-
const
|
|
550
|
-
|
|
551
|
-
if (caught.cause instanceof Caught) return escape(caught.cause);
|
|
552
|
-
for (let T = caught.state.constructor;; T = Object.getPrototypeOf(T)) {
|
|
553
|
-
for (const handler of [...SETUP.get(T) || []].reverse()) if (typeof handler == "object" && handler.catch) handlers.add(handler.catch);
|
|
554
|
-
if (T === State) break;
|
|
555
|
-
}
|
|
583
|
+
function report(kind, owner, error, key) {
|
|
584
|
+
const state = owner instanceof Model ? owner : owner && PARENT.get(owner);
|
|
585
|
+
if (!state) return REPORT.error(error);
|
|
556
586
|
try {
|
|
557
|
-
for (const handler of
|
|
587
|
+
for (const handler of [...stages(state.constructor, "catch")].reverse()) if ((error = handler.call(state, error, kind, key)) === void 0) return;
|
|
588
|
+
if (kind == "unused") console.warn(error);
|
|
589
|
+
else if (kind != "dead") REPORT.error(error);
|
|
558
590
|
} catch (err) {
|
|
559
|
-
|
|
560
|
-
return escape(err);
|
|
591
|
+
REPORT.error(err);
|
|
561
592
|
}
|
|
562
|
-
if (error.warning) console.warn(error);
|
|
563
|
-
else if (sync) throw error;
|
|
564
|
-
else escape(error);
|
|
565
|
-
}
|
|
566
|
-
function escape(err) {
|
|
567
|
-
queueMicrotask(() => {
|
|
568
|
-
throw err;
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
/** Error thrown by a handler replaying in dispatch, attributed to the State which queued it. */
|
|
572
|
-
function fault(err, owner) {
|
|
573
|
-
const state = owner instanceof State ? owner : owner && PARENT.get(owner);
|
|
574
|
-
if (state) report(new Caught.Effect(state, err));
|
|
575
|
-
else escape(err);
|
|
576
593
|
}
|
|
594
|
+
REPORT.as = report;
|
|
577
595
|
/**
|
|
578
596
|
* Hand a value stored by an owning writer to that property's adopter,
|
|
579
|
-
* creating one the first time a
|
|
580
|
-
* held a
|
|
597
|
+
* creating one the first time a Model is stored there. A property which has
|
|
598
|
+
* held a Model keeps its adopter, so a later non-Model value releases the
|
|
581
599
|
* previous child.
|
|
582
600
|
*/
|
|
583
601
|
function adopt(state, key, value) {
|
|
584
602
|
let keys = ADOPT.get(state);
|
|
585
603
|
if (!keys) {
|
|
586
|
-
if (!(value instanceof
|
|
604
|
+
if (!(value instanceof Model)) return;
|
|
587
605
|
ADOPT.set(state, keys = /* @__PURE__ */ new Map());
|
|
588
606
|
}
|
|
589
607
|
let claim = keys.get(key);
|
|
590
608
|
if (!claim) {
|
|
591
|
-
if (!(value instanceof
|
|
609
|
+
if (!(value instanceof Model)) return;
|
|
592
610
|
keys.set(key, claim = child(state));
|
|
593
611
|
}
|
|
594
612
|
claim(value);
|
|
@@ -598,101 +616,6 @@ function latest(getter) {
|
|
|
598
616
|
for (let next; next = LATEST.get(getter);) getter = next;
|
|
599
617
|
return getter;
|
|
600
618
|
}
|
|
601
|
-
/** Begin tracking live instances, so a hot patch can reach them. */
|
|
602
|
-
function track() {
|
|
603
|
-
LIVE ||= /* @__PURE__ */ new Set();
|
|
604
|
-
}
|
|
605
|
-
/**
|
|
606
|
-
* Move the members of `next` onto `prev`, which keeps its identity. Returns the
|
|
607
|
-
* live instances of `prev`, each needing a refresh.
|
|
608
|
-
*/
|
|
609
|
-
function patch(prev, next, own) {
|
|
610
|
-
const proto = prev.prototype;
|
|
611
|
-
const incoming = Object.getOwnPropertyDescriptors(next.prototype);
|
|
612
|
-
const keys = METHODS.get(prev);
|
|
613
|
-
const getters = GETTERS.get(prev);
|
|
614
|
-
const methods = /* @__PURE__ */ new Map();
|
|
615
|
-
const knownKeys = new Set(keys?.keys());
|
|
616
|
-
const knownGetters = new Set(getters?.keys());
|
|
617
|
-
let setup = SETUP.get(prev);
|
|
618
|
-
for (const handler of own) setup.delete(handler);
|
|
619
|
-
for (const handler of handlers(next)) {
|
|
620
|
-
if (!setup) SETUP.set(prev, setup = /* @__PURE__ */ new Set());
|
|
621
|
-
setup.add(handler);
|
|
622
|
-
}
|
|
623
|
-
for (const key of Reflect.ownKeys(next)) {
|
|
624
|
-
if (key == "prototype" || key == "length" || key == "name") continue;
|
|
625
|
-
if (Object.getOwnPropertyDescriptor(prev, key)?.configurable !== false) define(prev, key, Object.getOwnPropertyDescriptor(next, key));
|
|
626
|
-
}
|
|
627
|
-
const removed = /* @__PURE__ */ new Set();
|
|
628
|
-
for (const key of Object.getOwnPropertyNames(proto)) if (key != "constructor" && !(key in incoming)) {
|
|
629
|
-
const bind = keys?.get(key);
|
|
630
|
-
if (bind && Object.getOwnPropertyDescriptor(proto, key).get === bind) {
|
|
631
|
-
PAST.add(UNBIND.get(bind));
|
|
632
|
-
keys.delete(key);
|
|
633
|
-
}
|
|
634
|
-
removed.add(key);
|
|
635
|
-
Reflect.deleteProperty(proto, key);
|
|
636
|
-
getters?.delete(key);
|
|
637
|
-
}
|
|
638
|
-
for (const [key, desc] of Object.entries(incoming)) {
|
|
639
|
-
if (key == "constructor") continue;
|
|
640
|
-
const current = Object.getOwnPropertyDescriptor(proto, key);
|
|
641
|
-
if (typeof desc.value == "function") methods.set(key, desc.value);
|
|
642
|
-
if (current?.configurable === false) {
|
|
643
|
-
if (current.writable) proto[key] = desc.value;
|
|
644
|
-
continue;
|
|
645
|
-
}
|
|
646
|
-
if (current?.get && keys?.get(key) === current.get) PAST.add(UNBIND.get(current.get));
|
|
647
|
-
const getter = getters?.get(key);
|
|
648
|
-
if (getter) LATEST.set(getter, desc.get);
|
|
649
|
-
define(proto, key, {
|
|
650
|
-
...desc,
|
|
651
|
-
configurable: true
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
if (keys) {
|
|
655
|
-
for (let T = prev;; T = Object.getPrototypeOf(T)) {
|
|
656
|
-
for (const handler of SETUP.get(T) || []) if (typeof handler == "object" && handler.type) handler.type(prev);
|
|
657
|
-
if (T === State) break;
|
|
658
|
-
}
|
|
659
|
-
classify(prev, keys, getters);
|
|
660
|
-
}
|
|
661
|
-
const live = [];
|
|
662
|
-
for (const ref of LIVE) {
|
|
663
|
-
const state = ref.deref();
|
|
664
|
-
if (!state) LIVE.delete(ref);
|
|
665
|
-
else if (state instanceof prev) live.push(state);
|
|
666
|
-
}
|
|
667
|
-
const descendants = new Set([prev, ...live.map((state) => state.constructor)]);
|
|
668
|
-
for (const type of descendants) for (const child of SUBCLASSES.get(type) || []) descendants.add(child);
|
|
669
|
-
descendants.delete(prev);
|
|
670
|
-
for (const type of descendants) {
|
|
671
|
-
const inherit = METHODS.get(type);
|
|
672
|
-
const computed = GETTERS.get(type);
|
|
673
|
-
for (const [key, bind] of keys) if (!knownKeys.has(key) && !inherit.has(key)) inherit.set(key, bind);
|
|
674
|
-
for (const [key, get] of getters) if (!knownGetters.has(key) && !computed.has(key)) computed.set(key, get);
|
|
675
|
-
for (const key of removed) if (!(key in type.prototype)) {
|
|
676
|
-
inherit.delete(key);
|
|
677
|
-
computed.delete(key);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
for (const state of live) {
|
|
681
|
-
for (const [key, value] of methods) {
|
|
682
|
-
const desc = Object.getOwnPropertyDescriptor(state, key);
|
|
683
|
-
if (!desc) continue;
|
|
684
|
-
if (desc.set) desc.set.call(state, value);
|
|
685
|
-
else if (PAST.has(UNBIND.get(desc.value))) delete state[key];
|
|
686
|
-
}
|
|
687
|
-
for (const key of removed) if (PAST.has(UNBIND.get(Object.getOwnPropertyDescriptor(state, key)?.value))) delete state[key];
|
|
688
|
-
for (const [key, get] of GETTERS.get(state.constructor)) if (!knownGetters.has(key) && get === getters.get(key)) compute.call(state, get, key);
|
|
689
|
-
}
|
|
690
|
-
return live;
|
|
691
|
-
}
|
|
692
|
-
/** Lifecycle handlers registered on a class itself. */
|
|
693
|
-
function handlers(type) {
|
|
694
|
-
return [...SETUP.get(type) || []];
|
|
695
|
-
}
|
|
696
619
|
/** Random alphanumberic of length 6; always starts with a letter. */
|
|
697
620
|
function uid() {
|
|
698
621
|
return (.278 + Math.random() * .722).toString(36).substring(2, 8).toUpperCase();
|
|
@@ -708,5 +631,5 @@ function parent(child, value) {
|
|
|
708
631
|
}
|
|
709
632
|
|
|
710
633
|
//#endregion
|
|
711
|
-
export { PENDING, STORE,
|
|
634
|
+
export { GETTERS, LATEST, METHODS, Model, PENDING, SETUP, STORE, UNBIND, access, adopt, apply, children, classify, compute, event, owned, parent, trailing, uid, unbind, update };
|
|
712
635
|
//# sourceMappingURL=state.js.map
|