@expressive/mvc 0.84.3 → 0.86.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 +3 -3
- package/dist/caught.d.ts +5237 -0
- package/dist/caught.js +64 -0
- package/dist/caught.js.map +1 -0
- package/dist/context.d.ts +6 -1
- package/dist/context.js +16 -2
- package/dist/context.js.map +1 -1
- package/dist/dispatch.d.ts +32 -3
- package/dist/dispatch.js +95 -26
- package/dist/dispatch.js.map +1 -1
- package/dist/field/def.js +1 -1
- package/dist/field/get.js +1 -1
- package/dist/field/has.d.ts +11 -3
- package/dist/field/has.js +1 -1
- package/dist/field/has.js.map +1 -1
- package/dist/field/map.js +1 -1
- package/dist/field/ref.js +1 -1
- package/dist/field/set.js +5 -2
- package/dist/field/set.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -0
- package/dist/observable.d.ts +4 -4
- package/dist/observable.js +56 -29
- package/dist/observable.js.map +1 -1
- package/dist/runtime.d.ts +4 -13
- package/dist/runtime.js +4 -15
- package/dist/runtime.js.map +1 -1
- package/dist/state.d.ts +14 -3
- package/dist/state.js +62 -20
- package/dist/state.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Context } from "./context.js";
|
|
2
2
|
import { State, unbind } from "./state.js";
|
|
3
|
-
import {
|
|
3
|
+
import { Caught } from "./caught.js";
|
|
4
4
|
import { Component } from "./component.js";
|
|
5
|
+
import { pending } from "./dispatch.js";
|
|
5
6
|
import { def } from "./field/def.js";
|
|
6
7
|
import { get } from "./field/get.js";
|
|
7
8
|
import { has } from "./field/has.js";
|
|
8
9
|
import { map } from "./field/map.js";
|
|
9
10
|
import { ref } from "./field/ref.js";
|
|
10
11
|
import { set } from "./field/set.js";
|
|
11
|
-
export { Component, Context, State, def, State as default, get, has, map, ref, set,
|
|
12
|
+
export { Caught, Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Caught } from "./caught.js";
|
|
1
2
|
import { State, unbind } from "./state.js";
|
|
3
|
+
import { pending } from "./dispatch.js";
|
|
2
4
|
import { Context } from "./context.js";
|
|
3
5
|
import { def } from "./field/def.js";
|
|
4
6
|
import { set } from "./field/set.js";
|
|
@@ -7,6 +9,11 @@ import { get } from "./field/get.js";
|
|
|
7
9
|
import { has } from "./field/has.js";
|
|
8
10
|
import { map } from "./field/map.js";
|
|
9
11
|
import { ref } from "./field/ref.js";
|
|
10
|
-
import { transition } from "./runtime.js";
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
//#region src/index.ts
|
|
14
|
+
/** @deprecated Import `{ State }` as a named export. Adapter-augmented `State.*` types are not visible through the default alias. */
|
|
15
|
+
var src_default = State;
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { Caught, Component, Context, State, def, src_default as default, get, has, map, pending, ref, set, unbind };
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["export { def } from './field/def';\nexport { get } from './field/get';\nexport { has } from './field/has';\nexport { map } from './field/map';\nexport { set } from './field/set';\nexport { ref } from './field/ref';\n\nimport { State } from './state';\n\nexport { State, unbind } from './state';\n\n/** @deprecated Import `{ State }` as a named export. Adapter-augmented `State.*` types are not visible through the default alias. */\nexport default State;\nexport { Context } from './context';\nexport { Component } from './component';\nexport { pending } from './dispatch';\nexport { Caught } from './caught';\n"],"mappings":";;;;;;;;;;;;;;AAYA,kBAAe"}
|
package/dist/observable.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ declare function observer(state: object, create?: boolean): Observer | undefined
|
|
|
40
40
|
declare function touch(from: object, key: any): void;
|
|
41
41
|
declare function touch<T>(from: object, key: any, value?: T): T;
|
|
42
42
|
declare function listener<T extends object>(subject: T, callback: Observer.Notify, select?: Observer.Signal | Set<Observer.Signal>): () => boolean;
|
|
43
|
-
declare function
|
|
43
|
+
declare function queued<K extends Observer.Event>(state: object): K[] & PromiseLike<K[]>;
|
|
44
44
|
declare function event(state: object, key?: Observer.Event | null, silent?: boolean): void;
|
|
45
45
|
/**
|
|
46
46
|
* Create a side-effect which will update whenever values accessed change.
|
|
@@ -50,9 +50,9 @@ declare function event(state: object, key?: Observer.Event | null, silent?: bool
|
|
|
50
50
|
* @param callback - Function to invoke when values change.
|
|
51
51
|
* @param requireValues - If `true` will throw if accessing a value which is `undefined`.
|
|
52
52
|
*/
|
|
53
|
-
declare function watch<T extends object>(target: T, callback: Observer.Effect<Required<T>>, requireValues: true): () => void;
|
|
54
|
-
declare function watch<T extends object>(target: T, callback: Observer.Effect<T>, recursive?: boolean): () => void;
|
|
53
|
+
declare function watch<T extends object>(target: T, callback: Observer.Effect<Required<T>>, requireValues: true, transition?: (work: () => void) => void): () => void;
|
|
54
|
+
declare function watch<T extends object>(target: T, callback: Observer.Effect<T>, recursive?: boolean, transition?: (work: () => void) => void): () => void;
|
|
55
55
|
declare function capture(scope: (release: (update?: boolean | null) => void) => void): void;
|
|
56
56
|
//#endregion
|
|
57
|
-
export { Observer, capture, event, listener, observer,
|
|
57
|
+
export { Observer, capture, event, listener, observer, queued, touch, watch };
|
|
58
58
|
//# sourceMappingURL=observable.d.ts.map
|
package/dist/observable.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { enqueue } from "./dispatch.js";
|
|
1
|
+
import { enqueue, hold } from "./dispatch.js";
|
|
2
2
|
|
|
3
3
|
//#region src/observable.ts
|
|
4
4
|
const Observer = Symbol("Observer");
|
|
@@ -20,11 +20,18 @@ function observer(state, create) {
|
|
|
20
20
|
}
|
|
21
21
|
return o;
|
|
22
22
|
}
|
|
23
|
-
function observe(object, callback, required) {
|
|
23
|
+
function observe(object, callback, required, cleanup = []) {
|
|
24
24
|
const watching = /* @__PURE__ */ new Set();
|
|
25
|
+
const observing = {
|
|
26
|
+
callback,
|
|
27
|
+
watching,
|
|
28
|
+
required,
|
|
29
|
+
release: cleanup
|
|
30
|
+
};
|
|
25
31
|
const release = listener(object, (key) => {
|
|
26
|
-
if (watching.has(key)) return callback();
|
|
32
|
+
if (watching.has(key)) return observing.callback();
|
|
27
33
|
});
|
|
34
|
+
cleanup.push(release);
|
|
28
35
|
if (EffectContext) EffectContext.add((update) => {
|
|
29
36
|
if (update !== true) release();
|
|
30
37
|
});
|
|
@@ -33,21 +40,20 @@ function observe(object, callback, required) {
|
|
|
33
40
|
value: object.is,
|
|
34
41
|
writable: true
|
|
35
42
|
});
|
|
36
|
-
return Object.defineProperty(proxy, Observing, { value:
|
|
37
|
-
callback,
|
|
38
|
-
watching,
|
|
39
|
-
required
|
|
40
|
-
} });
|
|
43
|
+
return Object.defineProperty(proxy, Observing, { value: observing });
|
|
41
44
|
}
|
|
42
45
|
function touch(from, key, value) {
|
|
43
46
|
const active = from[Observing];
|
|
44
47
|
if (active) {
|
|
45
48
|
if (value === void 0 && arguments.length === 3 && active.required) throw new Error(`${Object.getPrototypeOf(from)}.${String(key)} is required in this context.`);
|
|
46
49
|
active.watching.add(key);
|
|
47
|
-
if (value instanceof Object && observer(value)) return observe(value, active.callback, active.required);
|
|
50
|
+
if (value instanceof Object && observer(value)) return observe(value, () => active.callback(), active.required, active.release);
|
|
48
51
|
}
|
|
49
52
|
return value;
|
|
50
53
|
}
|
|
54
|
+
function unobserve(observing) {
|
|
55
|
+
for (const release of observing.release) release();
|
|
56
|
+
}
|
|
51
57
|
function listener(subject, callback, select) {
|
|
52
58
|
const o = observer(subject, true);
|
|
53
59
|
if (select !== void 0 && !(select instanceof Set)) select = new Set([select]);
|
|
@@ -56,7 +62,7 @@ function listener(subject, callback, select) {
|
|
|
56
62
|
return () => o.listeners.delete(callback);
|
|
57
63
|
}
|
|
58
64
|
const EMPTY = Object.assign([], { then: Promise.prototype.then.bind(Promise.resolve([])) });
|
|
59
|
-
function
|
|
65
|
+
function queued(state) {
|
|
60
66
|
const o = observer(state);
|
|
61
67
|
if (!o?.events.size) return EMPTY;
|
|
62
68
|
const current = o.events;
|
|
@@ -75,17 +81,17 @@ function event(state, key, silent) {
|
|
|
75
81
|
if (key === null) {
|
|
76
82
|
if (!Object.getOwnPropertyDescriptor(state, Observer)) return;
|
|
77
83
|
state[Observer] = null;
|
|
78
|
-
return emit(o, key);
|
|
84
|
+
return emit(o, key, state);
|
|
79
85
|
}
|
|
80
|
-
if (key === void 0) return emit(o, true);
|
|
86
|
+
if (key === void 0) return emit(o, true, state);
|
|
81
87
|
if (!o.events.size && !silent) enqueue(() => {
|
|
82
|
-
emit(o, false);
|
|
88
|
+
emit(o, false, state);
|
|
83
89
|
o.events = /* @__PURE__ */ new Set();
|
|
84
|
-
});
|
|
90
|
+
}, void 0, state);
|
|
85
91
|
o.events.add(key);
|
|
86
|
-
if (!silent) emit(o, key);
|
|
92
|
+
if (!silent) emit(o, key, state);
|
|
87
93
|
}
|
|
88
|
-
function emit(o, key) {
|
|
94
|
+
function emit(o, key, subject) {
|
|
89
95
|
const { listeners, pending, ready } = o;
|
|
90
96
|
if (key === ready) return;
|
|
91
97
|
if (pending.size) {
|
|
@@ -97,49 +103,57 @@ function emit(o, key) {
|
|
|
97
103
|
for (const k of pending) for (const [callback, filter] of listeners) if (!filter || filter.has(k)) {
|
|
98
104
|
const after = callback(k);
|
|
99
105
|
if (after === null) listeners.delete(callback);
|
|
100
|
-
else if (after) enqueue(after);
|
|
106
|
+
else if (typeof after == "function") enqueue(after, void 0, subject);
|
|
101
107
|
}
|
|
102
108
|
if (key === null) listeners.clear();
|
|
103
109
|
else if (key === true) o.ready = true;
|
|
104
110
|
pending.clear();
|
|
105
111
|
}
|
|
106
|
-
function watch(target, callback, argument) {
|
|
112
|
+
function watch(target, callback, argument, transition) {
|
|
107
113
|
const o = observer(target, true);
|
|
108
114
|
let events = [];
|
|
109
115
|
let unset;
|
|
110
116
|
let reset;
|
|
111
117
|
let previous;
|
|
118
|
+
let latest;
|
|
112
119
|
let queued = false;
|
|
120
|
+
let suspense;
|
|
121
|
+
function resume() {
|
|
122
|
+
suspense?.();
|
|
123
|
+
suspense = void 0;
|
|
124
|
+
}
|
|
113
125
|
function invoke() {
|
|
114
|
-
if (observer(target) === null) return;
|
|
126
|
+
if (reset === null || observer(target) === null) return;
|
|
115
127
|
queued = false;
|
|
116
128
|
let ignore = true;
|
|
117
129
|
function onUpdate() {
|
|
118
130
|
events = [...o.events];
|
|
119
131
|
if (reset === null) return null;
|
|
120
132
|
if (ignore) {
|
|
121
|
-
if (queued) enqueue(invoke);
|
|
133
|
+
if (queued) enqueue(invoke, transition, target);
|
|
122
134
|
return;
|
|
123
135
|
}
|
|
124
136
|
ignore = true;
|
|
125
137
|
queued = true;
|
|
126
138
|
unset(true);
|
|
127
139
|
unset = void 0;
|
|
128
|
-
enqueue(invoke);
|
|
140
|
+
enqueue(invoke, transition, target);
|
|
129
141
|
}
|
|
130
142
|
function run(release) {
|
|
143
|
+
if (previous !== latest) unobserve(latest);
|
|
131
144
|
const proxy = observe(target, onUpdate, argument === true);
|
|
145
|
+
const current = latest = proxy[Observing];
|
|
132
146
|
const output = callback.call(proxy, proxy, events);
|
|
133
147
|
if (observer(target) === null) {
|
|
134
148
|
if (typeof output == "function") output(null);
|
|
135
149
|
if (release) release(null);
|
|
136
150
|
return;
|
|
137
151
|
}
|
|
138
|
-
if (previous && argument === false)
|
|
139
|
-
|
|
140
|
-
if (
|
|
152
|
+
if (previous && argument === false && !current.watching.size) previous.callback = onUpdate;
|
|
153
|
+
else {
|
|
154
|
+
if (previous) unobserve(previous);
|
|
155
|
+
previous = current;
|
|
141
156
|
}
|
|
142
|
-
previous = proxy;
|
|
143
157
|
ignore = false;
|
|
144
158
|
reset = output === null ? null : invoke;
|
|
145
159
|
unset = (key) => {
|
|
@@ -154,17 +168,30 @@ function watch(target, callback, argument) {
|
|
|
154
168
|
} catch (err) {
|
|
155
169
|
if (err instanceof Promise) {
|
|
156
170
|
reset = void 0;
|
|
157
|
-
|
|
171
|
+
const suspended = suspense = hold(true, transition);
|
|
172
|
+
const replay = () => {
|
|
173
|
+
if (suspense !== suspended) return;
|
|
174
|
+
suspense = void 0;
|
|
175
|
+
suspended(invoke);
|
|
176
|
+
};
|
|
177
|
+
err.then(replay, replay);
|
|
158
178
|
} else throw err;
|
|
159
179
|
}
|
|
160
180
|
}
|
|
161
181
|
const unlisten = listener(target, (key) => {
|
|
162
182
|
if (key === true) invoke();
|
|
163
|
-
else if (
|
|
164
|
-
|
|
183
|
+
else if (key === null) {
|
|
184
|
+
if (unset) unset(null);
|
|
185
|
+
resume();
|
|
186
|
+
reset = null;
|
|
187
|
+
} else if (!reset) {
|
|
188
|
+
suspense?.(false);
|
|
189
|
+
return reset;
|
|
190
|
+
}
|
|
165
191
|
});
|
|
166
192
|
function cleanup() {
|
|
167
193
|
if (unset) unset(false);
|
|
194
|
+
resume();
|
|
168
195
|
reset = null;
|
|
169
196
|
unlisten();
|
|
170
197
|
}
|
|
@@ -183,5 +210,5 @@ function capture(scope) {
|
|
|
183
210
|
}
|
|
184
211
|
|
|
185
212
|
//#endregion
|
|
186
|
-
export { Observer, capture, event, listener, observer,
|
|
213
|
+
export { Observer, capture, event, listener, observer, queued, touch, watch };
|
|
187
214
|
//# sourceMappingURL=observable.js.map
|
package/dist/observable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"observable.js","names":[],"sources":["../src/observable.ts"],"sourcesContent":["import { enqueue } from './dispatch';\n\ndeclare namespace Observer {\n /**\n * Update callback function.\n *\n * @param key -\n * - `string` - property which has updated.\n * - `false` - a normal update has completed.\n * - `true` - initial event; instance is ready.\n * - `null` - terminal event; instance is expired.\n */\n type Notify = (key: Signal) => (() => void) | null | void;\n\n type EffectCleanup = (update: boolean | null) => void;\n\n type Effect<T extends object> = (\n this: T,\n proxy: T,\n changed: readonly Event[]\n ) => EffectCleanup | Promise<void> | null | void;\n\n type Event = number | string | symbol;\n\n type Signal = Event | true | false | null;\n\n type Callback = () => void | null;\n}\n\ninterface Observer {\n /** Becomes `true` once the subject has emitted its initial event. */\n ready?: true;\n listeners: Map<Observer.Notify, Set<Observer.Signal> | undefined>;\n /** Recursion guard for an in-progress emit pass. */\n pending: Set<Observer.Signal>;\n /** Accumulator drained by the next microtask. */\n events: Set<Observer.Event>;\n}\n\ninterface Observing {\n callback: Observer.Callback;\n watching: Set<Observer.Signal>;\n required?: boolean;\n}\n\nconst Observer: unique symbol = Symbol('Observer');\nconst Observing: unique symbol = Symbol('Observing');\n\ninterface Observable { [Observer]?: Observer | null }\ninterface Observed { [Observing]?: Observing }\n\n/**\n * Fetch the dispatch bundle attached to an object.\n * - returns the bundle if active\n * - returns `null` if the subject has been terminated\n * - returns `undefined` if the subject was never observable\n *\n * With `create: true`, attaches a fresh bundle iff the slot is undefined.\n * A terminated (null) slot is not resurrected.\n */\nfunction observer(state: object, create: true): Observer;\nfunction observer(state: object, create?: boolean): Observer | undefined | null;\nfunction observer(state: object, create?: boolean) {\n const o = (state as Observable)[Observer];\n\n if (!o && create) {\n if (o === null)\n throw new Error(\n `${state} was destroyed - cannot be rendered, watched or updated.`\n );\n\n const value: Observer = {\n listeners: new Map(),\n pending: new Set(),\n events: new Set()\n };\n Object.defineProperty(state, Observer, { value, writable: true });\n return value;\n }\n\n return o;\n}\n\nfunction observe<T extends object>(\n object: T,\n callback: Observer.Callback,\n required?: boolean\n): T {\n const watching = new Set<Observer.Signal>();\n\n const release = listener(object, (key) => {\n if (watching.has(key)) return callback();\n });\n\n if (EffectContext)\n EffectContext.add((update) => {\n if (update !== true) release();\n });\n\n const proxy = Object.create(object) as T;\n\n if ('is' in object)\n Object.defineProperty(proxy, 'is', {\n value: (object as { is?: unknown }).is,\n writable: true\n });\n\n return Object.defineProperty(proxy, Observing, {\n value: { callback, watching, required } as Observing\n });\n}\n\nfunction touch(from: object, key: any): void;\nfunction touch<T>(from: object, key: any, value?: T): T;\nfunction touch(from: object, key: any, value?: any) {\n const active = (from as Observed)[Observing];\n\n if (active) {\n if (value === undefined && arguments.length === 3 && active.required)\n throw new Error(\n `${Object.getPrototypeOf(from)}.${String(key)} is required in this context.`\n );\n\n active.watching.add(key);\n\n if (value instanceof Object && observer(value))\n return observe(value, active.callback, active.required);\n }\n\n return value;\n}\n\nfunction listener<T extends object>(\n subject: T,\n callback: Observer.Notify,\n select?: Observer.Signal | Set<Observer.Signal>\n) {\n const o = observer(subject, true);\n\n if (select !== undefined && !(select instanceof Set))\n select = new Set([select]);\n\n if (o.ready && !select) callback(true);\n\n o.listeners.set(callback, select);\n\n return () => o.listeners.delete(callback);\n}\n\nconst EMPTY = Object.assign([], {\n then: Promise.prototype.then.bind(Promise.resolve([]))\n} as PromiseLike<never[]>);\n\nfunction pending<K extends Observer.Event>(\n state: object\n): K[] & PromiseLike<K[]> {\n const o = observer(state);\n if (!o?.events.size) return EMPTY;\n\n const current = o.events as Set<K>;\n const promise = new Promise<K[]>((res) => {\n const callback: Observer.Notify = () => {\n o.listeners.delete(callback);\n return () => res([...current]);\n };\n o.listeners.set(callback, undefined);\n });\n\n return Object.assign([...current], {\n then: promise.then.bind(promise)\n });\n}\n\nfunction event(state: object, key?: Observer.Event | null, silent?: boolean) {\n const o = observer(state, key === undefined);\n\n if (!o) return;\n\n if (key === null) {\n if (!Object.getOwnPropertyDescriptor(state, Observer)) return;\n\n (state as Observable)[Observer] = null;\n return emit(o, key);\n }\n\n if (key === undefined) return emit(o, true);\n\n if (!o.events.size && !silent)\n enqueue(() => {\n emit(o, false);\n o.events = new Set();\n });\n\n o.events.add(key);\n\n if (!silent) emit(o, key);\n}\n\nfunction emit(o: Observer, key: Observer.Signal): void {\n const { listeners, pending, ready } = o;\n\n if (key === ready) return;\n\n if (pending.size) {\n pending.add(key);\n return;\n }\n\n if (!ready && key !== null) pending.add(true);\n\n pending.add(key);\n\n for (const k of pending)\n for (const [callback, filter] of listeners)\n if (!filter || filter.has(k)) {\n const after = callback(k);\n if (after === null) listeners.delete(callback);\n else if (after) enqueue(after);\n }\n\n if (key === null) listeners.clear();\n else if (key === true) o.ready = true;\n\n pending.clear();\n}\n\n/**\n * Create a side-effect which will update whenever values accessed change.\n * Callback is called immediately and whenever values are stale.\n *\n * @param target - Instance of State to observe.\n * @param callback - Function to invoke when values change.\n * @param requireValues - If `true` will throw if accessing a value which is `undefined`.\n */\nfunction watch<T extends object>(\n target: T,\n callback: Observer.Effect<Required<T>>,\n requireValues: true\n): () => void;\n\nfunction watch<T extends object>(\n target: T,\n callback: Observer.Effect<T>,\n recursive?: boolean\n): () => void;\n\nfunction watch<T extends object>(\n target: T,\n callback: Observer.Effect<T>,\n argument?: boolean\n) {\n const o = observer(target, true);\n let events: readonly Observer.Event[] = [];\n let unset: ((update: boolean | null) => void) | undefined;\n let reset: (() => void) | null | undefined;\n let previous: T | undefined;\n let queued = false;\n\n function invoke() {\n if (observer(target) === null) return;\n\n queued = false;\n let ignore: boolean = true;\n\n function onUpdate() {\n events = [...o.events];\n\n if (reset === null) return null;\n if (ignore) {\n if (queued) enqueue(invoke);\n return;\n }\n\n ignore = true;\n queued = true;\n\n unset!(true);\n unset = undefined;\n\n enqueue(invoke);\n }\n\n function run(release?: (update?: boolean | null) => void) {\n const proxy = observe(target, onUpdate, argument === true);\n const output = callback.call(proxy, proxy, events);\n\n if (observer(target) === null) {\n if (typeof output == 'function') output(null);\n if (release) release(null);\n return;\n }\n\n if (previous && argument === false) {\n const { watching } = (proxy as Observed)[Observing]!;\n if (!watching.size)\n (previous as Observed)[Observing]!.watching.forEach((k) => watching.add(k));\n }\n \n previous = proxy;\n ignore = false;\n reset = output === null ? null : invoke;\n unset = (key) => {\n if (typeof output == 'function') output(key);\n if (release) release(key);\n };\n\n events = [];\n }\n\n try {\n if (argument !== false) capture(run);\n else run();\n } catch (err) {\n if (err instanceof Promise) {\n reset = undefined;\n err.then(invoke);\n } else {\n throw err;\n }\n }\n }\n\n const unlisten = listener(target, (key) => {\n if (key === true) invoke();\n else if (!reset) return reset;\n\n if (key === null && unset) unset(null);\n });\n\n function cleanup() {\n if (unset) unset(false);\n\n reset = null;\n unlisten();\n }\n\n if (EffectContext && argument !== false) EffectContext.add(cleanup);\n\n return cleanup;\n}\n\nlet EffectContext: Set<(update?: boolean | null) => void> | undefined;\n\nfunction capture(scope: (release: (update?: boolean | null) => void) => void) {\n const parent = EffectContext;\n const context = (EffectContext = new Set());\n\n try {\n scope((update) => context.forEach((fn) => fn(update)));\n } finally {\n EffectContext = parent;\n }\n}\n\nexport {\n listener,\n event,\n Observer,\n touch,\n pending,\n observer,\n watch,\n capture\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"observable.js","names":[],"sources":["../src/observable.ts"],"sourcesContent":["import { enqueue, hold } from './dispatch';\n\ndeclare namespace Observer {\n /**\n * Update callback function.\n *\n * @param key -\n * - `string` - property which has updated.\n * - `false` - a normal update has completed.\n * - `true` - initial event; instance is ready.\n * - `null` - terminal event; instance is expired.\n */\n type Notify = (key: Signal) => (() => void) | null | void;\n\n type EffectCleanup = (update: boolean | null) => void;\n\n type Effect<T extends object> = (\n this: T,\n proxy: T,\n changed: readonly Event[]\n ) => EffectCleanup | Promise<void> | null | void;\n\n type Event = number | string | symbol;\n\n type Signal = Event | true | false | null;\n\n type Callback = () => void | null;\n}\n\ninterface Observer {\n /** Becomes `true` once the subject has emitted its initial event. */\n ready?: true;\n listeners: Map<Observer.Notify, Set<Observer.Signal> | undefined>;\n /** Recursion guard for an in-progress emit pass. */\n pending: Set<Observer.Signal>;\n /** Accumulator drained by the next microtask. */\n events: Set<Observer.Event>;\n}\n\ninterface Observing {\n callback: Observer.Callback;\n watching: Set<Observer.Signal>;\n required?: boolean;\n release: (() => void)[];\n}\n\nconst Observer: unique symbol = Symbol('Observer');\nconst Observing: unique symbol = Symbol('Observing');\n\ninterface Observable { [Observer]?: Observer | null }\ninterface Observed { [Observing]?: Observing }\n\n/**\n * Fetch the dispatch bundle attached to an object.\n * - returns the bundle if active\n * - returns `null` if the subject has been terminated\n * - returns `undefined` if the subject was never observable\n *\n * With `create: true`, attaches a fresh bundle iff the slot is undefined.\n * A terminated (null) slot is not resurrected.\n */\nfunction observer(state: object, create: true): Observer;\nfunction observer(state: object, create?: boolean): Observer | undefined | null;\nfunction observer(state: object, create?: boolean) {\n const o = (state as Observable)[Observer];\n\n if (!o && create) {\n if (o === null)\n throw new Error(\n `${state} was destroyed - cannot be rendered, watched or updated.`\n );\n\n const value: Observer = {\n listeners: new Map(),\n pending: new Set(),\n events: new Set()\n };\n Object.defineProperty(state, Observer, { value, writable: true });\n return value;\n }\n\n return o;\n}\n\nfunction observe<T extends object>(\n object: T,\n callback: Observer.Callback,\n required?: boolean,\n cleanup: (() => void)[] = []\n): T {\n const watching = new Set<Observer.Signal>();\n const observing: Observing = { callback, watching, required, release: cleanup };\n\n const release = listener(object, (key) => {\n if (watching.has(key)) return observing.callback();\n });\n\n cleanup.push(release);\n\n if (EffectContext)\n EffectContext.add((update) => {\n if (update !== true) release();\n });\n\n const proxy = Object.create(object) as T;\n\n if ('is' in object)\n Object.defineProperty(proxy, 'is', {\n value: (object as { is?: unknown }).is,\n writable: true\n });\n\n return Object.defineProperty(proxy, Observing, { value: observing });\n}\n\nfunction touch(from: object, key: any): void;\nfunction touch<T>(from: object, key: any, value?: T): T;\nfunction touch(from: object, key: any, value?: any) {\n const active = (from as Observed)[Observing];\n\n if (active) {\n if (value === undefined && arguments.length === 3 && active.required)\n throw new Error(\n `${Object.getPrototypeOf(from)}.${String(key)} is required in this context.`\n );\n\n active.watching.add(key);\n\n if (value instanceof Object && observer(value))\n return observe(\n value,\n () => active.callback(),\n active.required,\n active.release\n );\n }\n\n return value;\n}\n\nfunction unobserve(observing: Observing) {\n for (const release of observing.release) release();\n}\n\nfunction listener<T extends object>(\n subject: T,\n callback: Observer.Notify,\n select?: Observer.Signal | Set<Observer.Signal>\n) {\n const o = observer(subject, true);\n\n if (select !== undefined && !(select instanceof Set))\n select = new Set([select]);\n\n if (o.ready && !select) callback(true);\n\n o.listeners.set(callback, select);\n\n return () => o.listeners.delete(callback);\n}\n\nconst EMPTY = Object.assign([], {\n then: Promise.prototype.then.bind(Promise.resolve([]))\n} as PromiseLike<never[]>);\n\nfunction queued<K extends Observer.Event>(\n state: object\n): K[] & PromiseLike<K[]> {\n const o = observer(state);\n if (!o?.events.size) return EMPTY;\n\n const current = o.events as Set<K>;\n const promise = new Promise<K[]>((res) => {\n const callback: Observer.Notify = () => {\n o.listeners.delete(callback);\n return () => res([...current]);\n };\n o.listeners.set(callback, undefined);\n });\n\n return Object.assign([...current], {\n then: promise.then.bind(promise)\n });\n}\n\nfunction event(state: object, key?: Observer.Event | null, silent?: boolean) {\n const o = observer(state, key === undefined);\n\n if (!o) return;\n\n if (key === null) {\n if (!Object.getOwnPropertyDescriptor(state, Observer)) return;\n\n (state as Observable)[Observer] = null;\n return emit(o, key, state);\n }\n\n if (key === undefined) return emit(o, true, state);\n\n if (!o.events.size && !silent)\n enqueue(() => {\n emit(o, false, state);\n o.events = new Set();\n }, undefined, state);\n\n o.events.add(key);\n\n if (!silent) emit(o, key, state);\n}\n\nfunction emit(o: Observer, key: Observer.Signal, subject: object): void {\n const { listeners, pending, ready } = o;\n\n if (key === ready) return;\n\n if (pending.size) {\n pending.add(key);\n return;\n }\n\n if (!ready && key !== null) pending.add(true);\n\n pending.add(key);\n\n for (const k of pending)\n for (const [callback, filter] of listeners)\n if (!filter || filter.has(k)) {\n const after = callback(k);\n if (after === null) listeners.delete(callback);\n else if (typeof after == 'function') enqueue(after, undefined, subject);\n }\n\n if (key === null) listeners.clear();\n else if (key === true) o.ready = true;\n\n pending.clear();\n}\n\n/**\n * Create a side-effect which will update whenever values accessed change.\n * Callback is called immediately and whenever values are stale.\n *\n * @param target - Instance of State to observe.\n * @param callback - Function to invoke when values change.\n * @param requireValues - If `true` will throw if accessing a value which is `undefined`.\n */\nfunction watch<T extends object>(\n target: T,\n callback: Observer.Effect<Required<T>>,\n requireValues: true,\n transition?: (work: () => void) => void\n): () => void;\n\nfunction watch<T extends object>(\n target: T,\n callback: Observer.Effect<T>,\n recursive?: boolean,\n transition?: (work: () => void) => void\n): () => void;\n\nfunction watch<T extends object>(\n target: T,\n callback: Observer.Effect<T>,\n argument?: boolean,\n transition?: (work: () => void) => void\n) {\n const o = observer(target, true);\n let events: readonly Observer.Event[] = [];\n let unset: ((update: boolean | null) => void) | undefined;\n let reset: (() => void) | null | undefined;\n let previous: Observing | undefined;\n let latest: Observing | undefined;\n let queued = false;\n let suspense: ReturnType<typeof hold>;\n\n function resume() {\n suspense?.();\n suspense = undefined;\n }\n\n function invoke() {\n if (reset === null || observer(target) === null) return;\n\n queued = false;\n let ignore: boolean = true;\n\n function onUpdate() {\n events = [...o.events];\n\n if (reset === null) return null;\n if (ignore) {\n if (queued) enqueue(invoke, transition, target);\n return;\n }\n\n ignore = true;\n queued = true;\n\n unset!(true);\n unset = undefined;\n\n enqueue(invoke, transition, target);\n }\n\n function run(release?: (update?: boolean | null) => void) {\n if (previous !== latest) unobserve(latest!);\n\n const proxy = observe(target, onUpdate, argument === true);\n const current = latest = (proxy as Observed)[Observing]!;\n const output = callback.call(proxy, proxy, events);\n\n if (observer(target) === null) {\n if (typeof output == 'function') output(null);\n if (release) release(null);\n return;\n }\n\n if (previous && argument === false && !current.watching.size)\n previous.callback = onUpdate;\n else {\n if (previous) unobserve(previous);\n previous = current;\n }\n\n ignore = false;\n reset = output === null ? null : invoke;\n unset = (key) => {\n if (typeof output == 'function') output(key);\n if (release) release(key);\n };\n\n events = [];\n }\n\n try {\n if (argument !== false) capture(run);\n else run();\n } catch (err) {\n if (err instanceof Promise) {\n reset = undefined;\n const suspended = suspense = hold(true, transition)!;\n const replay = () => {\n if (suspense !== suspended) return;\n suspense = undefined;\n suspended(invoke);\n };\n err.then(replay, replay);\n } else {\n throw err;\n }\n }\n }\n\n const unlisten = listener(target, (key) => {\n if (key === true) invoke();\n else if (key === null) {\n if (unset) unset(null);\n resume();\n reset = null;\n } else if (!reset) {\n suspense?.(false);\n return reset;\n }\n });\n\n function cleanup() {\n if (unset) unset(false);\n\n resume();\n reset = null;\n unlisten();\n }\n\n if (EffectContext && argument !== false) EffectContext.add(cleanup);\n\n return cleanup;\n}\n\nlet EffectContext: Set<(update?: boolean | null) => void> | undefined;\n\nfunction capture(scope: (release: (update?: boolean | null) => void) => void) {\n const parent = EffectContext;\n const context = (EffectContext = new Set());\n\n try {\n scope((update) => context.forEach((fn) => fn(update)));\n } finally {\n EffectContext = parent;\n }\n}\n\nexport {\n listener,\n event,\n Observer,\n touch,\n queued,\n observer,\n watch,\n capture\n};\n"],"mappings":"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"}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -38,8 +38,6 @@ interface HostRuntime {
|
|
|
38
38
|
jsxs(type: unknown, props: object, key?: unknown): Component.Node;
|
|
39
39
|
propsOf(node: unknown): Record<string, unknown>;
|
|
40
40
|
typeOf(node: unknown): unknown;
|
|
41
|
-
/** Non-urgent update bracket (e.g. React `startTransition`). Optional - see {@link transition}. */
|
|
42
|
-
transition?(work: () => void): void;
|
|
43
41
|
Fragment: unknown;
|
|
44
42
|
}
|
|
45
43
|
/**
|
|
@@ -50,10 +48,9 @@ interface HostRuntime {
|
|
|
50
48
|
declare const Fragment: unique symbol;
|
|
51
49
|
/**
|
|
52
50
|
* Register the host runtime. Idempotent for the same runtime - re-registering
|
|
53
|
-
* picks up members added since (e.g. an optional dev
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* routed around at the call sites instead.
|
|
51
|
+
* picks up members added since (e.g. an optional dev seam). Element mechanics
|
|
52
|
+
* the host leaves unset keep defaults that throw a setup-pointing error;
|
|
53
|
+
* `jsxDEV` is routed around at the call site instead.
|
|
57
54
|
*/
|
|
58
55
|
declare function host(runtime: HostRuntime): void;
|
|
59
56
|
declare function jsx(type: unknown, props: object, key?: unknown): Component.Node;
|
|
@@ -69,12 +66,6 @@ declare function isElement(node: unknown): boolean;
|
|
|
69
66
|
declare function typeOf(node: unknown): unknown;
|
|
70
67
|
/** Props carried by element `node`. */
|
|
71
68
|
declare function propsOf(node: unknown): Record<string, unknown>;
|
|
72
|
-
/**
|
|
73
|
-
* Mark synchronous work as non-urgent. `work` runs inline through the host
|
|
74
|
-
* scheduler; queued subscriber updates inherit the designation and replay it
|
|
75
|
-
* after dispatch. Without a host scheduler, normal timing is retained.
|
|
76
|
-
*/
|
|
77
|
-
declare function transition(work: () => void): void;
|
|
78
69
|
//#endregion
|
|
79
|
-
export { Fragment, Host, HostRuntime, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf,
|
|
70
|
+
export { Fragment, Host, HostRuntime, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
|
|
80
71
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { schedule } from "./dispatch.js";
|
|
2
|
-
|
|
3
1
|
//#region src/runtime.ts
|
|
4
2
|
/**
|
|
5
3
|
* Agnostic Fragment sentinel. The runtime entries translate it to the host's
|
|
@@ -23,10 +21,9 @@ const HOST = {
|
|
|
23
21
|
let registered;
|
|
24
22
|
/**
|
|
25
23
|
* Register the host runtime. Idempotent for the same runtime - re-registering
|
|
26
|
-
* picks up members added since (e.g. an optional dev
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* routed around at the call sites instead.
|
|
24
|
+
* picks up members added since (e.g. an optional dev seam). Element mechanics
|
|
25
|
+
* the host leaves unset keep defaults that throw a setup-pointing error;
|
|
26
|
+
* `jsxDEV` is routed around at the call site instead.
|
|
30
27
|
*/
|
|
31
28
|
function host(runtime) {
|
|
32
29
|
if (registered && registered !== runtime) throw new Error("A different JSX host is already registered for @expressive/mvc. Only one host adapter may be active per build.");
|
|
@@ -65,15 +62,7 @@ function typeOf(node) {
|
|
|
65
62
|
function propsOf(node) {
|
|
66
63
|
return HOST.propsOf(node);
|
|
67
64
|
}
|
|
68
|
-
/**
|
|
69
|
-
* Mark synchronous work as non-urgent. `work` runs inline through the host
|
|
70
|
-
* scheduler; queued subscriber updates inherit the designation and replay it
|
|
71
|
-
* after dispatch. Without a host scheduler, normal timing is retained.
|
|
72
|
-
*/
|
|
73
|
-
function transition(work) {
|
|
74
|
-
schedule(work, HOST.transition);
|
|
75
|
-
}
|
|
76
65
|
|
|
77
66
|
//#endregion
|
|
78
|
-
export { Fragment, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf,
|
|
67
|
+
export { Fragment, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
|
|
79
68
|
//# sourceMappingURL=runtime.js.map
|
package/dist/runtime.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import type { Component } from './component';\
|
|
1
|
+
{"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import type { Component } from './component';\n\n/**\n * Per-adapter interpretation manifest. Each adapter augments this interface to\n * declare how it renders; the first member is `node` - the element type produced\n * by `Component.render` (surfaced as `Component.Node`) - alongside `intrinsics`,\n * the host's tag map (surfaced as `JSX.IntrinsicElements`).\n *\n * ```ts\n * declare module '@expressive/mvc/runtime' {\n * interface Host {\n * node: React.ReactNode;\n * intrinsics: React.JSX.IntrinsicElements;\n * }\n * }\n * ```\n *\n * Only one adapter is expected per compilation; two augmenting the same member\n * with different types in the same build would conflict - by design.\n */\nexport interface Host { }\n\n/**\n * Host runtime, registered by an adapter (e.g. `@expressive/react`) as an\n * import side effect. One host per build - a second registration with a\n * different runtime throws.\n *\n * Members are ambient host capabilities: plain functions the host uniquely\n * owns, callable outside render - element mechanics always, plus optional\n * extras that fall back sanely when absent. Hook-shaped (render-resident)\n * capabilities do not belong here; those live with the adapter.\n */\nexport interface HostRuntime {\n childrenOf(children: unknown): Component.Node[];\n isElement(node: unknown): boolean;\n jsx(type: unknown, props: object, key?: unknown): Component.Node;\n jsxDEV?(type: unknown, props: object, key?: unknown, isStatic?: boolean, source?: object, self?: unknown): Component.Node;\n jsxs(type: unknown, props: object, key?: unknown): Component.Node;\n propsOf(node: unknown): Record<string, unknown>;\n typeOf(node: unknown): unknown;\n Fragment: unknown;\n}\n\n/**\n * Agnostic Fragment sentinel. The runtime entries translate it to the host's\n * Fragment on element creation; `typeOf` translates back, so identity checks\n * against this value hold for fragments from either pragma.\n */\nexport const Fragment = Symbol.for('@expressive/mvc.Fragment');\n\n/** Default for seams only a registered host can provide. */\nfunction absent(): never {\n throw new Error(\n 'No JSX host is registered for @expressive/mvc. ' +\n \"Import a host adapter (e.g. '@expressive/react') before anything renders - \" +\n 'typically as the first import of your application entry module.'\n );\n}\n\nconst HOST: HostRuntime = {\n childrenOf: absent,\n isElement: absent,\n jsx: absent,\n jsxs: absent,\n propsOf: absent,\n typeOf: absent,\n Fragment\n};\n\nlet registered: HostRuntime | undefined;\n\n/**\n * Register the host runtime. Idempotent for the same runtime - re-registering\n * picks up members added since (e.g. an optional dev seam). Element mechanics\n * the host leaves unset keep defaults that throw a setup-pointing error;\n * `jsxDEV` is routed around at the call site instead.\n */\nexport function host(runtime: HostRuntime) {\n if (registered && registered !== runtime)\n throw new Error(\n 'A different JSX host is already registered for @expressive/mvc. ' +\n 'Only one host adapter may be active per build.'\n );\n\n registered = runtime;\n Object.assign(HOST, runtime);\n}\n\n/** Translate the agnostic Fragment sentinel to the host's Fragment. */\nfunction hostType(type: unknown): unknown {\n return type === Fragment ? HOST.Fragment : type;\n}\n\nexport function jsx(type: unknown, props: object, key?: unknown): Component.Node {\n return HOST.jsx(hostType(type), props, key);\n}\n\nexport function jsxs(type: unknown, props: object, key?: unknown): Component.Node {\n return HOST.jsxs(hostType(type), props, key);\n}\n\n/** Dev-transpiled element creation. Hosts without a `jsxDEV` of their own fall\n * back to the production entries (prod-only host under a dev build). */\nexport function jsxDEV(\n type: unknown,\n props: object,\n key?: unknown,\n isStatic?: boolean,\n source?: object,\n self?: unknown\n): Component.Node {\n return HOST.jsxDEV\n ? HOST.jsxDEV(hostType(type), props, key, isStatic, source, self)\n : isStatic\n ? jsxs(type, props, key)\n : jsx(type, props, key);\n}\n\n/** Flatten `children` to an array of nodes, per the host's semantics. */\nexport function childrenOf(children: unknown): Component.Node[] {\n return HOST.childrenOf(children);\n}\n\n/** Is `node` a host element? */\nexport function isElement(node: unknown): boolean {\n return HOST.isElement(node);\n}\n\n/** Element type of `node`; host Fragments surface as the agnostic `Fragment`. */\nexport function typeOf(node: unknown): unknown {\n const type = HOST.typeOf(node);\n return type === HOST.Fragment ? Fragment : type;\n}\n\n/** Props carried by element `node`. */\nexport function propsOf(node: unknown): Record<string, unknown> {\n return HOST.propsOf(node);\n}\n\n"],"mappings":";;;;;;AAgDA,MAAa,WAAW,OAAO,IAAI,2BAA2B;;AAG9D,SAAS,SAAgB;AACvB,OAAM,IAAI,MACR,4LAGD;;AAGH,MAAM,OAAoB;CACxB,YAAY;CACZ,WAAW;CACX,KAAK;CACL,MAAM;CACN,SAAS;CACT,QAAQ;CACR;CACD;AAED,IAAI;;;;;;;AAQJ,SAAgB,KAAK,SAAsB;AACzC,KAAI,cAAc,eAAe,QAC/B,OAAM,IAAI,MACR,iHAED;AAEH,cAAa;AACb,QAAO,OAAO,MAAM,QAAQ;;;AAI9B,SAAS,SAAS,MAAwB;AACxC,QAAO,SAAS,WAAW,KAAK,WAAW;;AAG7C,SAAgB,IAAI,MAAe,OAAe,KAA+B;AAC/E,QAAO,KAAK,IAAI,SAAS,KAAK,EAAE,OAAO,IAAI;;AAG7C,SAAgB,KAAK,MAAe,OAAe,KAA+B;AAChF,QAAO,KAAK,KAAK,SAAS,KAAK,EAAE,OAAO,IAAI;;;;AAK9C,SAAgB,OACd,MACA,OACA,KACA,UACA,QACA,MACgB;AAChB,QAAO,KAAK,SACR,KAAK,OAAO,SAAS,KAAK,EAAE,OAAO,KAAK,UAAU,QAAQ,KAAK,GAC/D,WACE,KAAK,MAAM,OAAO,IAAI,GACtB,IAAI,MAAM,OAAO,IAAI;;;AAI7B,SAAgB,WAAW,UAAqC;AAC9D,QAAO,KAAK,WAAW,SAAS;;;AAIlC,SAAgB,UAAU,MAAwB;AAChD,QAAO,KAAK,UAAU,KAAK;;;AAI7B,SAAgB,OAAO,MAAwB;CAC7C,MAAM,OAAO,KAAK,OAAO,KAAK;AAC9B,QAAO,SAAS,KAAK,WAAW,WAAW;;;AAI7C,SAAgB,QAAQ,MAAwC;AAC9D,QAAO,KAAK,QAAQ,KAAK"}
|
package/dist/state.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Context } from "./context.js";
|
|
2
2
|
import { event } from "./observable.js";
|
|
3
|
+
import { Caught } from "./caught.js";
|
|
3
4
|
|
|
4
5
|
//#region src/state.d.ts
|
|
5
6
|
/** Internal state assigned to states. */
|
|
@@ -52,6 +53,14 @@ declare namespace State {
|
|
|
52
53
|
* observed and constructor args applied. May return a cleanup function.
|
|
53
54
|
*/
|
|
54
55
|
after?(this: T, self: T): void | (() => void);
|
|
56
|
+
/**
|
|
57
|
+
* Receives a `Caught` mvc reports for this State or a subclass - most-derived
|
|
58
|
+
* class first, last registered first. Return it (or a replacement) to pass it
|
|
59
|
+
* on; return nothing to handle it; throw to let it escape uncaught. Passed off
|
|
60
|
+
* the end, a warning logs and anything else is thrown - to the writer for a
|
|
61
|
+
* destroyed write, else uncaught.
|
|
62
|
+
*/
|
|
63
|
+
catch?(this: T, error: Caught): Caught | void;
|
|
55
64
|
}
|
|
56
65
|
/** Object overlay to override values and methods on a state. */
|
|
57
66
|
type Assign<T> = Record<string, unknown> & { [K in Field<T>]?: T[K] extends ((...args: infer A) => infer R) ? (this: T, ...args: A) => R : T[K] };
|
|
@@ -208,7 +217,7 @@ declare abstract class State {
|
|
|
208
217
|
* Properties which are not managed by this state will be ignored.
|
|
209
218
|
*
|
|
210
219
|
* @param assign - Object with properties to update.
|
|
211
|
-
* @param silent - If true, listeners will not be notified. If state is destroyed,
|
|
220
|
+
* @param silent - If true, listeners will not be notified. If state is destroyed, drops the update without reporting it.
|
|
212
221
|
* @returns Array of keys updated, syncronously contains keys updated immediately and may be resolved (to itself) when all updates are settled.
|
|
213
222
|
*/
|
|
214
223
|
set(assign?: State.Assign<this>, silent?: boolean): State.Updated<this>;
|
|
@@ -332,9 +341,11 @@ declare function access(state: State, property: string, required?: boolean): any
|
|
|
332
341
|
*
|
|
333
342
|
* 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.
|
|
334
343
|
*
|
|
335
|
-
*
|
|
344
|
+
* A destroyed state reports the write - thrown to the writer unless a `catch` handler takes it - and returns `false`; `silent` skips both, and dispatch.
|
|
336
345
|
*/
|
|
337
346
|
declare function update<T>(state: State, key: State.Event<T>, value: T, silent?: boolean, own?: boolean): boolean;
|
|
347
|
+
/** Error thrown by a handler replaying in dispatch, attributed to the State which queued it. */
|
|
348
|
+
declare function fault(err: unknown, owner?: object): void;
|
|
338
349
|
/** Random alphanumberic of length 6; always starts with a letter. */
|
|
339
350
|
declare function uid(): string;
|
|
340
351
|
declare function unbind<T extends Function>(fn: T): T;
|
|
@@ -348,5 +359,5 @@ declare function unbind<T extends Function>(fn?: T): T | undefined;
|
|
|
348
359
|
declare function parent(child: object): State | null | undefined;
|
|
349
360
|
declare function parent(child: object, value: State | null): boolean;
|
|
350
361
|
//#endregion
|
|
351
|
-
export { PENDING, STORE, State, access, apply, children, compute, event, parent, uid, unbind, update };
|
|
362
|
+
export { PENDING, STORE, State, access, apply, children, compute, event, fault, parent, uid, unbind, update };
|
|
352
363
|
//# sourceMappingURL=state.d.ts.map
|