@expressive/mvc 0.85.0 → 0.87.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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hot.js","names":[],"sources":["../src/hot.ts"],"sourcesContent":["import { rechain } from './component';\nimport { event, observer } from './observable';\nimport { State, handlers, patch, track } from './state';\n\ninterface Entry {\n type: Function;\n shape: string;\n kinds: Record<string, 'get' | 'accessor' | 'fn'>;\n own: ReturnType<typeof handlers>;\n}\n\ninterface Replaced {\n /** Module id the class was accepted under. */\n id: string;\n /** Local declaration name of the class. */\n name: string;\n /** Class live instances belong to. */\n prev: State.Extends;\n /** Class that took its place. */\n next: State.Extends;\n}\n\nconst MODULES = new Map<string, Record<string, Entry>>();\nconst LISTENERS = new Set<(event: Replaced) => void>();\nconst REFRESH = Symbol.for('@expressive/mvc.refresh');\nconst PRIVATE = /(?:^|[\\s;{}*])#[\\w$]+(?=[\\s=;(}])/;\n\nfunction isState(value: unknown): value is State.Extends {\n return typeof value == 'function' && value.prototype instanceof State;\n}\n\n/** What a patch cannot carry: class source less its members, and member kinds. */\nfunction describe(type: Function): Entry {\n const text = Function.prototype.toString;\n const kinds: Entry['kinds'] = {};\n let shape = text.call(type);\n\n for (const target of [type.prototype, type])\n for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(target)))\n for (const fn of [desc.value, desc.get, desc.set])\n if (typeof fn == 'function' && fn !== type) {\n shape = shape.replace(text.call(fn), '');\n if (target !== type) kinds[key] = desc.set ? 'accessor' : desc.get ? 'get' : 'fn';\n }\n\n return { type, shape: shape.replace(/\\s+/g, ' '), kinds, own: handlers(type as State.Extends) };\n}\n\nfunction compatible(prev: Entry, next: Entry) {\n if (prev.shape !== next.shape || PRIVATE.test(next.shape)) return false;\n if (Object.getPrototypeOf(prev.type) !== Object.getPrototypeOf(next.type)) return false;\n\n for (const key in next.kinds)\n if (key in prev.kinds && prev.kinds[key] !== next.kinds[key]) return false;\n\n return true;\n}\n\n/**\n * Keep a module's State classes stable across runs. A class seen before is\n * patched with its replacement and returned in its place, refreshing live\n * instances; one whose shape or parent changed is returned as-is, and\n * reported to `replaced` listeners before `accept` returns.\n */\nfunction accept<T extends Record<string, unknown>>(id: string, classes: T): T {\n let known = MODULES.get(id);\n\n if (!known) MODULES.set(id, (known = {}));\n\n const output: Record<string, unknown> = { ...classes };\n const refresh = new Set<State>();\n const replace: Replaced[] = [];\n let patched = false;\n\n track();\n\n for (const [name, type] of Object.entries(classes)) {\n if (!isState(type)) continue;\n\n const prev = known[name];\n\n if (prev?.type === type) continue;\n\n const next = describe(type);\n\n if (!prev || !compatible(prev, next)) {\n if (prev) replace.push({ id, name, prev: prev.type as State.Extends, next: type });\n known[name] = next;\n continue;\n }\n\n try {\n for (const state of patch(prev.type as State.Extends, type, prev.own)) refresh.add(state);\n patched = true;\n known[name] = { ...next, type: prev.type };\n output[name] = prev.type;\n } catch (error) {\n console.error(error);\n replace.push({ id, name, prev: prev.type as State.Extends, next: type });\n known[name] = next;\n }\n }\n\n if (patched) rechain();\n\n for (const state of refresh) if (observer(state)?.ready) event(state, REFRESH);\n\n for (const event of replace)\n for (const listener of LISTENERS)\n try {\n listener(event);\n } catch (error) {\n console.error(error);\n }\n\n return output as T;\n}\n\n/**\n * Observe classes `accept` replaced instead of patching. Fires synchronously\n * inside `accept`, while the module re-runs, so a host can retire instances of\n * `prev` before anything resolves the module again.\n */\nfunction replaced(listener: (event: Replaced) => void): () => void {\n LISTENERS.add(listener);\n return () => void LISTENERS.delete(listener);\n}\n\nexport { accept, replaced };\nexport type { Replaced };\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,0BAAU,IAAI,KAAoC;AACxD,MAAM,4BAAY,IAAI,KAAgC;AACtD,MAAM,UAAU,OAAO,IAAI,0BAA0B;AACrD,MAAM,UAAU;AAEhB,SAAS,QAAQ,OAAwC;AACvD,QAAO,OAAO,SAAS,cAAc,MAAM,qBAAqB;;;AAIlE,SAAS,SAAS,MAAuB;CACvC,MAAM,OAAO,SAAS,UAAU;CAChC,MAAM,QAAwB,EAAE;CAChC,IAAI,QAAQ,KAAK,KAAK,KAAK;AAE3B,MAAK,MAAM,UAAU,CAAC,KAAK,WAAW,KAAK,CACzC,MAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,OAAO,0BAA0B,OAAO,CAAC,CAChF,MAAK,MAAM,MAAM;EAAC,KAAK;EAAO,KAAK;EAAK,KAAK;EAAI,CAC/C,KAAI,OAAO,MAAM,cAAc,OAAO,MAAM;AAC1C,UAAQ,MAAM,QAAQ,KAAK,KAAK,GAAG,EAAE,GAAG;AACxC,MAAI,WAAW,KAAM,OAAM,OAAO,KAAK,MAAM,aAAa,KAAK,MAAM,QAAQ;;AAGrF,QAAO;EAAE;EAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI;EAAE;EAAO,KAAK,SAAS,KAAsB;EAAE;;AAGjG,SAAS,WAAW,MAAa,MAAa;AAC5C,KAAI,KAAK,UAAU,KAAK,SAAS,QAAQ,KAAK,KAAK,MAAM,CAAE,QAAO;AAClE,KAAI,OAAO,eAAe,KAAK,KAAK,KAAK,OAAO,eAAe,KAAK,KAAK,CAAE,QAAO;AAElF,MAAK,MAAM,OAAO,KAAK,MACrB,KAAI,OAAO,KAAK,SAAS,KAAK,MAAM,SAAS,KAAK,MAAM,KAAM,QAAO;AAEvE,QAAO;;;;;;;;AAST,SAAS,OAA0C,IAAY,SAAe;CAC5E,IAAI,QAAQ,QAAQ,IAAI,GAAG;AAE3B,KAAI,CAAC,MAAO,SAAQ,IAAI,IAAK,QAAQ,EAAE,CAAE;CAEzC,MAAM,SAAkC,EAAE,GAAG,SAAS;CACtD,MAAM,0BAAU,IAAI,KAAY;CAChC,MAAM,UAAsB,EAAE;CAC9B,IAAI,UAAU;AAEd,QAAO;AAEP,MAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,QAAQ,EAAE;AAClD,MAAI,CAAC,QAAQ,KAAK,CAAE;EAEpB,MAAM,OAAO,MAAM;AAEnB,MAAI,MAAM,SAAS,KAAM;EAEzB,MAAM,OAAO,SAAS,KAAK;AAE3B,MAAI,CAAC,QAAQ,CAAC,WAAW,MAAM,KAAK,EAAE;AACpC,OAAI,KAAM,SAAQ,KAAK;IAAE;IAAI;IAAM,MAAM,KAAK;IAAuB,MAAM;IAAM,CAAC;AAClF,SAAM,QAAQ;AACd;;AAGF,MAAI;AACF,QAAK,MAAM,SAAS,MAAM,KAAK,MAAuB,MAAM,KAAK,IAAI,CAAE,SAAQ,IAAI,MAAM;AACzF,aAAU;AACV,SAAM,QAAQ;IAAE,GAAG;IAAM,MAAM,KAAK;IAAM;AAC1C,UAAO,QAAQ,KAAK;WACb,OAAO;AACd,WAAQ,MAAM,MAAM;AACpB,WAAQ,KAAK;IAAE;IAAI;IAAM,MAAM,KAAK;IAAuB,MAAM;IAAM,CAAC;AACxE,SAAM,QAAQ;;;AAIlB,KAAI,QAAS,UAAS;AAEtB,MAAK,MAAM,SAAS,QAAS,KAAI,SAAS,MAAM,EAAE,MAAO,OAAM,OAAO,QAAQ;AAE9E,MAAK,MAAM,SAAS,QAClB,MAAK,MAAM,YAAY,UACrB,KAAI;AACF,WAAS,MAAM;UACR,OAAO;AACd,UAAQ,MAAM,MAAM;;AAG1B,QAAO;;;;;;;AAQT,SAAS,SAAS,UAAiD;AACjE,WAAU,IAAI,SAAS;AACvB,cAAa,KAAK,UAAU,OAAO,SAAS"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Context } from "./context.js";
2
2
  import { State, unbind } from "./state.js";
3
+ import { Caught } from "./caught.js";
3
4
  import { Component } from "./component.js";
4
5
  import { pending } from "./dispatch.js";
5
6
  import { def } from "./field/def.js";
@@ -8,4 +9,4 @@ 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, pending, ref, set, unbind };
12
+ export { Caught, Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
- import { pending } from "./dispatch.js";
1
+ import { Caught } from "./caught.js";
2
2
  import { State, unbind } from "./state.js";
3
+ import { pending } from "./dispatch.js";
3
4
  import { Context } from "./context.js";
4
5
  import { def } from "./field/def.js";
5
6
  import { set } from "./field/set.js";
@@ -9,4 +10,10 @@ import { has } from "./field/has.js";
9
10
  import { map } from "./field/map.js";
10
11
  import { ref } from "./field/ref.js";
11
12
 
12
- export { Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
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"}
@@ -3,6 +3,8 @@ import { enqueue, hold } from "./dispatch.js";
3
3
  //#region src/observable.ts
4
4
  const Observer = Symbol("Observer");
5
5
  const Observing = Symbol("Observing");
6
+ /** Event every observer treats as watched, to force a refresh. */
7
+ const REFRESH = Symbol.for("@expressive/mvc.refresh");
6
8
  function observer(state, create) {
7
9
  const o = state[Observer];
8
10
  if (!o && create) {
@@ -20,16 +22,18 @@ function observer(state, create) {
20
22
  }
21
23
  return o;
22
24
  }
23
- function observe(object, callback, required) {
25
+ function observe(object, callback, required, cleanup = []) {
24
26
  const watching = /* @__PURE__ */ new Set();
25
27
  const observing = {
26
28
  callback,
27
29
  watching,
28
- required
30
+ required,
31
+ release: cleanup
29
32
  };
30
33
  const release = listener(object, (key) => {
31
- if (watching.has(key)) return observing.callback();
34
+ if (watching.has(key) || key === REFRESH) return observing.callback();
32
35
  });
36
+ cleanup.push(release);
33
37
  if (EffectContext) EffectContext.add((update) => {
34
38
  if (update !== true) release();
35
39
  });
@@ -45,10 +49,13 @@ function touch(from, key, value) {
45
49
  if (active) {
46
50
  if (value === void 0 && arguments.length === 3 && active.required) throw new Error(`${Object.getPrototypeOf(from)}.${String(key)} is required in this context.`);
47
51
  active.watching.add(key);
48
- if (value instanceof Object && observer(value)) return observe(value, () => active.callback(), active.required);
52
+ if (value instanceof Object && observer(value)) return observe(value, () => active.callback(), active.required, active.release);
49
53
  }
50
54
  return value;
51
55
  }
56
+ function unobserve(observing) {
57
+ for (const release of observing.release) release();
58
+ }
52
59
  function listener(subject, callback, select) {
53
60
  const o = observer(subject, true);
54
61
  if (select !== void 0 && !(select instanceof Set)) select = new Set([select]);
@@ -76,17 +83,17 @@ function event(state, key, silent) {
76
83
  if (key === null) {
77
84
  if (!Object.getOwnPropertyDescriptor(state, Observer)) return;
78
85
  state[Observer] = null;
79
- return emit(o, key);
86
+ return emit(o, key, state);
80
87
  }
81
- if (key === void 0) return emit(o, true);
88
+ if (key === void 0) return emit(o, true, state);
82
89
  if (!o.events.size && !silent) enqueue(() => {
83
- emit(o, false);
90
+ emit(o, false, state);
84
91
  o.events = /* @__PURE__ */ new Set();
85
- });
92
+ }, void 0, state);
86
93
  o.events.add(key);
87
- if (!silent) emit(o, key);
94
+ if (!silent) emit(o, key, state);
88
95
  }
89
- function emit(o, key) {
96
+ function emit(o, key, subject) {
90
97
  const { listeners, pending, ready } = o;
91
98
  if (key === ready) return;
92
99
  if (pending.size) {
@@ -98,7 +105,7 @@ function emit(o, key) {
98
105
  for (const k of pending) for (const [callback, filter] of listeners) if (!filter || filter.has(k)) {
99
106
  const after = callback(k);
100
107
  if (after === null) listeners.delete(callback);
101
- else if (after) enqueue(after);
108
+ else if (typeof after == "function") enqueue(after, void 0, subject);
102
109
  }
103
110
  if (key === null) listeners.clear();
104
111
  else if (key === true) o.ready = true;
@@ -110,6 +117,7 @@ function watch(target, callback, argument, transition) {
110
117
  let unset;
111
118
  let reset;
112
119
  let previous;
120
+ let latest;
113
121
  let queued = false;
114
122
  let suspense;
115
123
  function resume() {
@@ -124,25 +132,30 @@ function watch(target, callback, argument, transition) {
124
132
  events = [...o.events];
125
133
  if (reset === null) return null;
126
134
  if (ignore) {
127
- if (queued) enqueue(invoke, transition);
135
+ if (queued) enqueue(invoke, transition, target);
128
136
  return;
129
137
  }
130
138
  ignore = true;
131
139
  queued = true;
132
140
  unset(true);
133
141
  unset = void 0;
134
- enqueue(invoke, transition);
142
+ enqueue(invoke, transition, target);
135
143
  }
136
144
  function run(release) {
145
+ if (previous !== latest) unobserve(latest);
137
146
  const proxy = observe(target, onUpdate, argument === true);
147
+ const current = latest = proxy[Observing];
138
148
  const output = callback.call(proxy, proxy, events);
139
149
  if (observer(target) === null) {
140
150
  if (typeof output == "function") output(null);
141
151
  if (release) release(null);
142
152
  return;
143
153
  }
144
- if (previous && argument === false && !proxy[Observing].watching.size) previous[Observing].callback = onUpdate;
145
- else previous = proxy;
154
+ if (previous && argument === false && !current.watching.size) previous.callback = onUpdate;
155
+ else {
156
+ if (previous) unobserve(previous);
157
+ previous = current;
158
+ }
146
159
  ignore = false;
147
160
  reset = output === null ? null : invoke;
148
161
  unset = (key) => {
@@ -1 +1 @@
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}\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 const observing: Observing = { callback, watching, required };\n\n const release = listener(object, (key) => {\n if (watching.has(key)) return observing.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, { 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(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 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);\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 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: T | 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);\n return;\n }\n\n ignore = true;\n queued = true;\n\n unset!(true);\n unset = undefined;\n\n enqueue(invoke, transition);\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 && !(proxy as Observed)[Observing]!.watching.size)\n (previous as Observed)[Observing]!.callback = onUpdate;\n else\n previous = proxy;\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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"}
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\n/** Event every observer treats as watched, to force a refresh. */\nconst REFRESH = Symbol.for('@expressive/mvc.refresh');\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) || key === REFRESH) 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
@@ -1,3 +1,4 @@
1
+ import { hot_d_exports } from "./hot.js";
1
2
  import { Component } from "./component.js";
2
3
 
3
4
  //#region src/runtime.d.ts
@@ -67,5 +68,5 @@ declare function typeOf(node: unknown): unknown;
67
68
  /** Props carried by element `node`. */
68
69
  declare function propsOf(node: unknown): Record<string, unknown>;
69
70
  //#endregion
70
- export { Fragment, Host, HostRuntime, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
71
+ export { Fragment, Host, HostRuntime, childrenOf, host, hot_d_exports as hot, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
71
72
  //# sourceMappingURL=runtime.d.ts.map
package/dist/runtime.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { hot_exports } from "./hot.js";
2
+
1
3
  //#region src/runtime.ts
2
4
  /**
3
5
  * Agnostic Fragment sentinel. The runtime entries translate it to the host's
@@ -64,5 +66,5 @@ function propsOf(node) {
64
66
  }
65
67
 
66
68
  //#endregion
67
- export { Fragment, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
69
+ export { Fragment, childrenOf, host, hot_exports as hot, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
68
70
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
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"}
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\nexport * as hot from './hot';\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. */
@@ -7,6 +8,8 @@ declare const STORE: WeakMap<State, Record<string | number | symbol, unknown>>;
7
8
  /** States under construction - added on `new`, removed when activated or released.
8
9
  * Also carries work to run at the deadline, which `def` uses to bound its registry. */
9
10
  declare const PENDING: Set<State | (() => void)>;
11
+ /** External lifecycle listeners for any given State class. */
12
+ type Handler = State.Init<any> | State.On<any>;
10
13
  declare namespace State {
11
14
  /** Any type of State, using own class constructor as its identifier. */
12
15
  type Extends<T extends State = State> = (abstract new (...args: any[]) => T) & typeof State;
@@ -52,11 +55,21 @@ declare namespace State {
52
55
  * observed and constructor args applied. May return a cleanup function.
53
56
  */
54
57
  after?(this: T, self: T): void | (() => void);
58
+ /**
59
+ * Receives a `Caught` mvc reports for this State or a subclass - most-derived
60
+ * class first, last registered first. Return it (or a replacement) to pass it
61
+ * on; return nothing to handle it; throw to let it escape uncaught. Passed off
62
+ * the end, a warning logs and anything else is thrown - to the writer for a
63
+ * destroyed write, else uncaught.
64
+ */
65
+ catch?(this: T, error: Caught): Caught | void;
55
66
  }
56
67
  /** Object overlay to override values and methods on a state. */
57
- 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] };
68
+ 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] };
58
69
  /** Subset of `keyof T` not defined by base State. **/
59
- type Field<T> = Exclude<keyof T, keyof State>;
70
+ type Property<T> = Exclude<keyof T, keyof State>;
71
+ /** Managed subset of Property<T> - excludes unmanaged `_` keys. **/
72
+ type Field<T> = Exclude<Property<T>, `_${string}`>;
60
73
  /** Any valid key for state, including but not limited to Field<T>. */
61
74
  type Event<T = State> = Field<T> | number | symbol | (string & {});
62
75
  /** Any event signal dispatched to listeners, including lifecycle meta events. */
@@ -208,7 +221,7 @@ declare abstract class State {
208
221
  * Properties which are not managed by this state will be ignored.
209
222
  *
210
223
  * @param assign - Object with properties to update.
211
- * @param silent - If true, listeners will not be notified. If state is destroyed, will squash update without throwing.
224
+ * @param silent - If true, listeners will not be notified. If state is destroyed, drops the update without reporting it.
212
225
  * @returns Array of keys updated, syncronously contains keys updated immediately and may be resolved (to itself) when all updates are settled.
213
226
  */
214
227
  set(assign?: State.Assign<this>, silent?: boolean): State.Updated<this>;
@@ -321,6 +334,11 @@ declare function compute(this: State, getter: (self: any) => unknown, key: strin
321
334
  * @param silent - If an update does occur, listeners will not be refreshed automatically.
322
335
  */
323
336
  declare function apply(state: State, key: string, config: State.Apply, silent?: boolean): void;
337
+ /**
338
+ * Pending States constructed after this one - in a parent, the products of
339
+ * its own initializers, until the last one it kept.
340
+ */
341
+ declare function trailing(state: State): State[];
324
342
  /**
325
343
  * Report States adopted by a parent - those already held, then each one
326
344
  * claimed later. Returns a callback to stop watching.
@@ -332,9 +350,20 @@ declare function access(state: State, property: string, required?: boolean): any
332
350
  *
333
351
  * 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
352
  *
335
- * If `silent` is true, the update will not dispatch events and will return `false` instead of throwing if state is destroyed.
353
+ * 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
354
  */
337
355
  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
+ /**
361
+ * Move the members of `next` onto `prev`, which keeps its identity. Returns the
362
+ * live instances of `prev`, each needing a refresh.
363
+ */
364
+ declare function patch(prev: State.Extends, next: State.Extends, own: Handler[]): State[];
365
+ /** Lifecycle handlers registered on a class itself. */
366
+ declare function handlers(type: State.Extends): Handler[];
338
367
  /** Random alphanumberic of length 6; always starts with a letter. */
339
368
  declare function uid(): string;
340
369
  declare function unbind<T extends Function>(fn: T): T;
@@ -348,5 +377,5 @@ declare function unbind<T extends Function>(fn?: T): T | undefined;
348
377
  declare function parent(child: object): State | null | undefined;
349
378
  declare function parent(child: object, value: State | null): boolean;
350
379
  //#endregion
351
- export { PENDING, STORE, State, access, apply, children, compute, event, parent, uid, unbind, update };
380
+ export { PENDING, STORE, State, access, apply, children, compute, event, fault, handlers, parent, patch, track, trailing, uid, unbind, update };
352
381
  //# sourceMappingURL=state.d.ts.map