@expressive/mvc 0.87.0 → 0.88.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 +2 -2
- package/dist/component.d.ts +31 -11
- package/dist/component.js +76 -49
- package/dist/component.js.map +1 -1
- package/dist/context.d.ts +3 -1
- package/dist/context.js +30 -12
- 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.js +3 -3
- package/dist/field/def.js.map +1 -1
- package/dist/field/get.js +21 -5
- package/dist/field/get.js.map +1 -1
- package/dist/field/has.js +1 -1
- package/dist/field/map.js +1 -1
- package/dist/field/ref.js +1 -1
- package/dist/field/set.js +1 -1
- package/dist/hot.d.ts +1 -4
- package/dist/hot.js +122 -10
- package/dist/hot.js.map +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +2 -3
- 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 +78 -5
- package/dist/jsx-runtime.js +69 -2
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/state.d.ts +66 -38
- package/dist/state.js +73 -164
- 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.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Context } from "./context.js";
|
|
2
2
|
import { event } from "./observable.js";
|
|
3
|
-
import { Caught } from "./caught.js";
|
|
4
3
|
|
|
5
4
|
//#region src/state.d.ts
|
|
6
5
|
/** Internal state assigned to states. */
|
|
@@ -9,7 +8,16 @@ declare const STORE: WeakMap<State, Record<string | number | symbol, unknown>>;
|
|
|
9
8
|
* Also carries work to run at the deadline, which `def` uses to bound its registry. */
|
|
10
9
|
declare const PENDING: Set<State | (() => void)>;
|
|
11
10
|
/** External lifecycle listeners for any given State class. */
|
|
12
|
-
type Handler = State.
|
|
11
|
+
type Handler = State.On<any>;
|
|
12
|
+
declare const SETUP: WeakMap<State.Extends<State>, Set<Handler>>;
|
|
13
|
+
/** Reference bound instance methods, or their getter, to real one. */
|
|
14
|
+
declare const UNBIND: WeakMap<any, any>;
|
|
15
|
+
/** List of methods defined by a given type. */
|
|
16
|
+
declare const METHODS: WeakMap<Function, Map<string, (value: any) => void>>;
|
|
17
|
+
/** List of reactive getters defined by a given type. */
|
|
18
|
+
declare const GETTERS: WeakMap<Function, Map<string, () => unknown>>;
|
|
19
|
+
/** Replacement for a getter captured by live computed properties, for hot patching. */
|
|
20
|
+
declare const LATEST: WeakMap<Function, Function>;
|
|
13
21
|
declare namespace State {
|
|
14
22
|
/** Any type of State, using own class constructor as its identifier. */
|
|
15
23
|
type Extends<T extends State = State> = (abstract new (...args: any[]) => T) & typeof State;
|
|
@@ -32,10 +40,7 @@ declare namespace State {
|
|
|
32
40
|
* will observe). Returned function will run when state is destroyed.
|
|
33
41
|
*/
|
|
34
42
|
type Init<T extends State = State> = (this: T, thisArg: T) => Promise<void> | (() => void) | Args<T> | Assign<T> | void;
|
|
35
|
-
/**
|
|
36
|
-
* Lifecycle handlers for `State.on`, keyed by when they run. A bare `Init`
|
|
37
|
-
* function passed to `on` is sugar for `{ before }`.
|
|
38
|
-
*/
|
|
43
|
+
/** Lifecycle handlers for `State.on`, keyed by when they run. */
|
|
39
44
|
interface On<T extends State = State> {
|
|
40
45
|
/**
|
|
41
46
|
* Per-class setup, run once when the class is first bootstrapped - before
|
|
@@ -45,24 +50,32 @@ declare namespace State {
|
|
|
45
50
|
*/
|
|
46
51
|
type?(type: State.Extends<T>): void;
|
|
47
52
|
/**
|
|
48
|
-
* Per-instance
|
|
49
|
-
*
|
|
50
|
-
*
|
|
53
|
+
* Per-instance, once constructed - before own values are observed and
|
|
54
|
+
* before constructor args and `new()`. May return a cleanup, constructor
|
|
55
|
+
* args, or an assign overlay.
|
|
51
56
|
*/
|
|
52
|
-
|
|
57
|
+
setup?(this: T, self: T): void | (() => void) | Promise<void> | Args<T> | Assign<T>;
|
|
53
58
|
/**
|
|
54
|
-
* Per-instance
|
|
55
|
-
*
|
|
59
|
+
* Per-instance, once ready - after own values are observed, constructor
|
|
60
|
+
* args applied and `new()` has run. May return a cleanup function.
|
|
56
61
|
*/
|
|
57
|
-
|
|
62
|
+
ready?(this: T, self: T): void | (() => void);
|
|
58
63
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* the end, a warning logs and anything else is thrown - to the writer for a
|
|
63
|
-
* destroyed write, else uncaught.
|
|
64
|
+
* Runs each time a method is bound to an instance - first access,
|
|
65
|
+
* reassignment, and the rebind after a hot patch - with the key, the bound
|
|
66
|
+
* function and the instance. Tooling and development use.
|
|
64
67
|
*/
|
|
65
|
-
|
|
68
|
+
method?(this: T, key: string, fn: Function, self: T): void;
|
|
69
|
+
/**
|
|
70
|
+
* Receives what an effect, refreshing getter or async initializer of this State
|
|
71
|
+
* or a subclass threw, a destroyed write, or an instance never activated - with
|
|
72
|
+
* its `kind` (`effect`, `getter`, `setup`, `dead`, `unused`) and `key` where
|
|
73
|
+
* one applies. Most-derived class first, last registered first, each once. Return the error
|
|
74
|
+
* (or another) to pass it on; return nothing to handle it; throw to let it escape.
|
|
75
|
+
* Passed off the end, a destroyed write outputs nothing, `unused` warns,
|
|
76
|
+
* anything else escapes uncaught.
|
|
77
|
+
*/
|
|
78
|
+
catch?(this: T, error: unknown, kind: 'effect' | 'getter' | 'setup' | 'dead' | 'unused', key?: string): unknown;
|
|
66
79
|
}
|
|
67
80
|
/** Object overlay to override values and methods on a state. */
|
|
68
81
|
type Assign<T> = Record<string, unknown> & { [K in Property<T>]?: T[K] extends ((...args: infer A) => infer R) ? (this: T, ...args: A) => R : T[K] };
|
|
@@ -210,6 +223,18 @@ declare abstract class State {
|
|
|
210
223
|
* @returns Function to cancel listener.
|
|
211
224
|
*/
|
|
212
225
|
get<T extends State>(type: State.Type<T>, callback: Context.Expect<T>, downstream?: boolean): () => void;
|
|
226
|
+
/** Owner of this State. Throws if it has none. */
|
|
227
|
+
get<T extends typeof State>(type: T & (typeof State extends T ? unknown : never), required?: true): State;
|
|
228
|
+
/** Owner of this State. Undefined if it has none. */
|
|
229
|
+
get<T extends typeof State>(type: T & (typeof State extends T ? unknown : never), required: boolean): State | undefined;
|
|
230
|
+
/**
|
|
231
|
+
* Run a callback for each State this one owns - those owned now, then each
|
|
232
|
+
* one as it activates. Callback may return a function, called when that State
|
|
233
|
+
* is destroyed.
|
|
234
|
+
*
|
|
235
|
+
* @returns Function to stop watching.
|
|
236
|
+
*/
|
|
237
|
+
get<T extends typeof State>(type: T & (typeof State extends T ? unknown : never), callback: (child: State) => void | (() => void), downstream: true): () => void;
|
|
213
238
|
/**
|
|
214
239
|
* Get update in progress.
|
|
215
240
|
*
|
|
@@ -221,7 +246,7 @@ declare abstract class State {
|
|
|
221
246
|
* Properties which are not managed by this state will be ignored.
|
|
222
247
|
*
|
|
223
248
|
* @param assign - Object with properties to update.
|
|
224
|
-
* @param silent - If true, listeners will not be notified. If state is destroyed,
|
|
249
|
+
* @param silent - If true, listeners will not be notified. If state is destroyed, stores the update without reporting it.
|
|
225
250
|
* @returns Array of keys updated, syncronously contains keys updated immediately and may be resolved (to itself) when all updates are settled.
|
|
226
251
|
*/
|
|
227
252
|
set(assign?: State.Assign<this>, silent?: boolean): State.Updated<this>;
|
|
@@ -255,7 +280,7 @@ declare abstract class State {
|
|
|
255
280
|
*/
|
|
256
281
|
set(key: State.Event<this>): State.Updated<this>;
|
|
257
282
|
/**
|
|
258
|
-
* Declare an end to updates. This event is final
|
|
283
|
+
* Declare an end to updates. This event is final - later writes are stored but never dispatched.
|
|
259
284
|
* This event can be watched for as well, to run cleanup logic and internally will remove all listeners.
|
|
260
285
|
*
|
|
261
286
|
* @param status - `null` to end updates.
|
|
@@ -304,16 +329,18 @@ declare abstract class State {
|
|
|
304
329
|
/**
|
|
305
330
|
* Register a lifecycle handler for this State and its subclasses.
|
|
306
331
|
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
* `after` (per-instance, at the `new()` slot).
|
|
332
|
+
* Hooks by cadence - `type` (per-class, at bootstrap), `setup` (per-instance,
|
|
333
|
+
* before values are observed), `ready` (per-instance, after `new()`), and
|
|
334
|
+
* `method` (per method binding). A function alone is a `setup` handler. A
|
|
335
|
+
* function returned from `setup` or `ready` runs when the instance is destroyed.
|
|
312
336
|
*
|
|
313
337
|
* @returns Function to remove the handler.
|
|
314
338
|
*/
|
|
315
|
-
static on<T extends State>(this: State.Extends<T>,
|
|
339
|
+
static on<T extends State>(this: State.Extends<T>, setup: NonNullable<State.On<T>['setup']>): () => boolean;
|
|
340
|
+
static on<T extends State>(this: State.Extends<T>, handler: State.On<T>): () => boolean;
|
|
316
341
|
}
|
|
342
|
+
/** Bind own configurable methods of a type and collect its reactive getters. */
|
|
343
|
+
declare function classify(type: State.Extends, keys: Map<string, (value: any) => void>, getters: Map<string, () => unknown>): void;
|
|
317
344
|
/**
|
|
318
345
|
* Install a reactive computed property on a state instance, derived from a prototype
|
|
319
346
|
* getter or an arity-bearing `set` factory.
|
|
@@ -344,26 +371,27 @@ declare function trailing(state: State): State[];
|
|
|
344
371
|
* claimed later. Returns a callback to stop watching.
|
|
345
372
|
*/
|
|
346
373
|
declare function children(state: State, callback: (child: State) => void): () => boolean;
|
|
374
|
+
/**
|
|
375
|
+
* Report States owned by this one - those active now, then each one as it
|
|
376
|
+
* activates. A function returned by `callback` runs when that State is destroyed.
|
|
377
|
+
*/
|
|
378
|
+
declare function owned(state: State, callback: (child: State) => void | (() => void)): () => undefined;
|
|
347
379
|
declare function access(state: State, property: string, required?: boolean): any;
|
|
348
380
|
/**
|
|
349
381
|
* Update a property on a state instance and notify listeners.
|
|
350
382
|
*
|
|
351
383
|
* 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.
|
|
352
384
|
*
|
|
353
|
-
* A destroyed state
|
|
385
|
+
* A destroyed state stores the write without dispatch, reports it unless `silent`, and returns `false`.
|
|
354
386
|
*/
|
|
355
387
|
declare function update<T>(state: State, key: State.Event<T>, value: T, silent?: boolean, own?: boolean): boolean;
|
|
356
|
-
/** Error thrown by a handler replaying in dispatch, attributed to the State which queued it. */
|
|
357
|
-
declare function fault(err: unknown, owner?: object): void;
|
|
358
|
-
/** Begin tracking live instances, so a hot patch can reach them. */
|
|
359
|
-
declare function track(): void;
|
|
360
388
|
/**
|
|
361
|
-
*
|
|
362
|
-
*
|
|
389
|
+
* Hand a value stored by an owning writer to that property's adopter,
|
|
390
|
+
* creating one the first time a State is stored there. A property which has
|
|
391
|
+
* held a State keeps its adopter, so a later non-State value releases the
|
|
392
|
+
* previous child.
|
|
363
393
|
*/
|
|
364
|
-
declare function
|
|
365
|
-
/** Lifecycle handlers registered on a class itself. */
|
|
366
|
-
declare function handlers(type: State.Extends): Handler[];
|
|
394
|
+
declare function adopt(state: State, key: unknown, value: unknown): void;
|
|
367
395
|
/** Random alphanumberic of length 6; always starts with a letter. */
|
|
368
396
|
declare function uid(): string;
|
|
369
397
|
declare function unbind<T extends Function>(fn: T): T;
|
|
@@ -377,5 +405,5 @@ declare function unbind<T extends Function>(fn?: T): T | undefined;
|
|
|
377
405
|
declare function parent(child: object): State | null | undefined;
|
|
378
406
|
declare function parent(child: object, value: State | null): boolean;
|
|
379
407
|
//#endregion
|
|
380
|
-
export { PENDING, STORE, State, access, apply, children, compute, event,
|
|
408
|
+
export { GETTERS, type Handler, LATEST, METHODS, PENDING, SETUP, STORE, State, UNBIND, access, adopt, apply, children, classify, compute, event, owned, parent, trailing, uid, unbind, update };
|
|
381
409
|
//# sourceMappingURL=state.d.ts.map
|
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;
|
|
@@ -22,12 +22,6 @@ 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. */
|
|
@@ -40,6 +34,8 @@ let ANNOUNCED = false;
|
|
|
40
34
|
/** Adopters for managed properties which have held a child State. */
|
|
41
35
|
const ADOPT = /* @__PURE__ */ new WeakMap();
|
|
42
36
|
const CHILDREN = /* @__PURE__ */ new WeakMap();
|
|
37
|
+
const OWNS = /* @__PURE__ */ new WeakMap();
|
|
38
|
+
const OWNED = /* @__PURE__ */ new WeakMap();
|
|
43
39
|
var State = class State {
|
|
44
40
|
/**
|
|
45
41
|
* Whether an instance activated with no enclosing context registers itself
|
|
@@ -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 (State
|
|
59
|
+
if (arg1 === State) return typeof arg2 == "function" ? owned(self, arg2) : observed(this, arg1, owner(self, arg2));
|
|
60
|
+
if (State.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;
|
|
@@ -105,18 +102,8 @@ 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);
|
|
@@ -129,6 +116,9 @@ define(State.prototype, "toString", { value() {
|
|
|
129
116
|
define(State, "toString", { value() {
|
|
130
117
|
return this.name;
|
|
131
118
|
} });
|
|
119
|
+
function observed(from, key, value) {
|
|
120
|
+
return value instanceof State ? 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);
|
|
@@ -147,7 +137,6 @@ function init(state, ...args) {
|
|
|
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 !== State; 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
|
}
|
|
@@ -232,10 +232,9 @@ function bootstrap(T) {
|
|
|
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
240
|
if (type === State) continue;
|
|
@@ -245,12 +244,6 @@ function bootstrap(T) {
|
|
|
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 === State ? /* @__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.
|
|
@@ -339,7 +339,7 @@ function compute(getter, key) {
|
|
|
339
339
|
console.warn(`An exception was thrown while initializing ${this}.${key}.`);
|
|
340
340
|
throw err;
|
|
341
341
|
}
|
|
342
|
-
if (!(err instanceof Promise)) report(
|
|
342
|
+
if (!(err instanceof Promise)) report("getter", this, err, key);
|
|
343
343
|
}
|
|
344
344
|
update(this, key, next, !isAsync);
|
|
345
345
|
};
|
|
@@ -461,6 +461,26 @@ function children(state, callback) {
|
|
|
461
461
|
set.add(callback);
|
|
462
462
|
return () => set.delete(callback);
|
|
463
463
|
}
|
|
464
|
+
function owner(state, required) {
|
|
465
|
+
const found = PARENT.get(state);
|
|
466
|
+
if (found || required === false) return found || void 0;
|
|
467
|
+
throw new Error(`${state} has no owner.`);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Report States owned by this one - those active now, then each one as it
|
|
471
|
+
* activates. A function returned by `callback` runs when that State is destroyed.
|
|
472
|
+
*/
|
|
473
|
+
function owned(state, callback) {
|
|
474
|
+
function each(child) {
|
|
475
|
+
const done = callback(child);
|
|
476
|
+
if (typeof done == "function") listener(child, () => void done(), null);
|
|
477
|
+
}
|
|
478
|
+
OWNS.get(state)?.forEach(each);
|
|
479
|
+
let set = OWNED.get(state);
|
|
480
|
+
if (!set) OWNED.set(state, set = /* @__PURE__ */ new Set());
|
|
481
|
+
set.add(each);
|
|
482
|
+
return () => void set.delete(each);
|
|
483
|
+
}
|
|
464
484
|
/** Currently accumulating export. Stores real values of placeholder properties such as ref() or child states. */
|
|
465
485
|
let EXPORT;
|
|
466
486
|
function values(state) {
|
|
@@ -524,15 +544,16 @@ function assign(state, data, silent) {
|
|
|
524
544
|
*
|
|
525
545
|
* 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
546
|
*
|
|
527
|
-
* A destroyed state
|
|
547
|
+
* A destroyed state stores the write without dispatch, reports it unless `silent`, and returns `false`.
|
|
528
548
|
*/
|
|
529
549
|
function update(state, key, value, silent, own) {
|
|
550
|
+
const store = STORE.get(state);
|
|
551
|
+
if (value instanceof State) value = value.is;
|
|
530
552
|
if (observer(state) === null) {
|
|
531
|
-
if (!silent) report(new
|
|
553
|
+
if (!silent) report("dead", state, /* @__PURE__ */ new Error(`Tried to update ${state}.${String(key)} but state is destroyed.`), String(key));
|
|
554
|
+
store[key] = value;
|
|
532
555
|
return false;
|
|
533
556
|
}
|
|
534
|
-
const store = STORE.get(state);
|
|
535
|
-
if (value instanceof State) value = value.is;
|
|
536
557
|
if (key in store && value === store[key]) return false;
|
|
537
558
|
store[key] = value;
|
|
538
559
|
if (!silent) event(state, key);
|
|
@@ -540,40 +561,23 @@ function update(state, key, value, silent, own) {
|
|
|
540
561
|
return true;
|
|
541
562
|
}
|
|
542
563
|
/**
|
|
543
|
-
* Pass
|
|
544
|
-
* first - until one returns nothing. Passed off
|
|
545
|
-
*
|
|
546
|
-
*
|
|
564
|
+
* Pass an error along `catch` handlers - most-derived class first, last registered
|
|
565
|
+
* first, one on several classes once at the outermost - until one returns nothing. Passed off
|
|
566
|
+
* the end, a destroyed write outputs nothing, `unused` warns, anything else escapes uncaught;
|
|
567
|
+
* so does a handler's throw.
|
|
547
568
|
*/
|
|
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
|
-
}
|
|
569
|
+
function report(kind, owner, error, key) {
|
|
570
|
+
const state = owner instanceof State ? owner : owner && PARENT.get(owner);
|
|
571
|
+
if (!state) return REPORT.error(error);
|
|
556
572
|
try {
|
|
557
|
-
for (const handler of
|
|
573
|
+
for (const handler of [...stages(state.constructor, "catch")].reverse()) if ((error = handler.call(state, error, kind, key)) === void 0) return;
|
|
574
|
+
if (kind == "unused") console.warn(error);
|
|
575
|
+
else if (kind != "dead") REPORT.error(error);
|
|
558
576
|
} catch (err) {
|
|
559
|
-
|
|
560
|
-
return escape(err);
|
|
577
|
+
REPORT.error(err);
|
|
561
578
|
}
|
|
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
579
|
}
|
|
580
|
+
REPORT.as = report;
|
|
577
581
|
/**
|
|
578
582
|
* Hand a value stored by an owning writer to that property's adopter,
|
|
579
583
|
* creating one the first time a State is stored there. A property which has
|
|
@@ -598,101 +602,6 @@ function latest(getter) {
|
|
|
598
602
|
for (let next; next = LATEST.get(getter);) getter = next;
|
|
599
603
|
return getter;
|
|
600
604
|
}
|
|
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
605
|
/** Random alphanumberic of length 6; always starts with a letter. */
|
|
697
606
|
function uid() {
|
|
698
607
|
return (.278 + Math.random() * .722).toString(36).substring(2, 8).toUpperCase();
|
|
@@ -708,5 +617,5 @@ function parent(child, value) {
|
|
|
708
617
|
}
|
|
709
618
|
|
|
710
619
|
//#endregion
|
|
711
|
-
export { PENDING, STORE, State, access, apply, children, compute, event,
|
|
620
|
+
export { GETTERS, LATEST, METHODS, PENDING, SETUP, STORE, State, UNBIND, access, adopt, apply, children, classify, compute, event, owned, parent, trailing, uid, unbind, update };
|
|
712
621
|
//# sourceMappingURL=state.js.map
|