@expressive/mvc 0.84.3 → 0.85.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/dist/context.d.ts CHANGED
@@ -54,6 +54,11 @@ declare class Context {
54
54
  */
55
55
  pop(): void;
56
56
  }
57
+ /**
58
+ * Add `value` to the context `state` was added to. A context-less `state` holds
59
+ * it instead - every context adding `state` later adds its held children too.
60
+ */
61
+ declare function join(state: State, value: State): () => void;
57
62
  //#endregion
58
- export { Context };
63
+ export { Context, join };
59
64
  //# sourceMappingURL=context.d.ts.map
package/dist/context.js CHANGED
@@ -3,6 +3,7 @@ import { State, uid } from "./state.js";
3
3
 
4
4
  //#region src/context.ts
5
5
  const LOOKUP = /* @__PURE__ */ new WeakMap();
6
+ const HELD = /* @__PURE__ */ new WeakMap();
6
7
  let ROOT;
7
8
  var Context = class Context {
8
9
  static get root() {
@@ -170,8 +171,10 @@ var Context = class Context {
170
171
  onDone.forEach((r) => r());
171
172
  onDone.clear();
172
173
  }
174
+ const held = Array.from(HELD.get(I) || [], (child) => this.add(child));
173
175
  function remove() {
174
176
  cleanup.delete(remove);
177
+ held.forEach((done) => done());
175
178
  flush();
176
179
  }
177
180
  cleanup.set(remove, remove);
@@ -206,7 +209,18 @@ var Context = class Context {
206
209
  Object.defineProperty(Context.prototype, "toString", { value() {
207
210
  return `Context-${this.id}`;
208
211
  } });
212
+ /**
213
+ * Add `value` to the context `state` was added to. A context-less `state` holds
214
+ * it instead - every context adding `state` later adds its held children too.
215
+ */
216
+ function join(state, value) {
217
+ const ctx = LOOKUP.get(state.is);
218
+ if (ctx) return ctx.add(value);
219
+ const held = HELD.get(state) || /* @__PURE__ */ new Set();
220
+ HELD.set(state, held.add(value));
221
+ return () => held.delete(value);
222
+ }
209
223
 
210
224
  //#endregion
211
- export { Context };
225
+ export { Context, join };
212
226
  //# sourceMappingURL=context.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import { listener } from \"./observable\";\nimport { event, State, uid } from \"./state\";\n\nconst LOOKUP = new WeakMap<State, Context>();\nlet ROOT: Context;\n\ntype Accept<T extends State = State> =\n | T\n | State.Type<T>\n | Record<string | number, T | State.Type<T>>;\n\ntype Expect<T extends State = State> = (\n state: T,\n downstream: boolean,\n) => (() => void) | void;\n\ndeclare namespace Context {\n export { Accept, Expect };\n}\n\nclass Context {\n static get root(): Context {\n return ROOT ??= new Context();\n }\n\n /** Get the context for a State. Adapters may override to provide framework context. */\n static get(state?: State): Context {\n return state && LOOKUP.get(state.is) || Context.root;\n }\n\n public id = uid();\n public parent?: Context;\n public scope = new Set<Context>();\n public consume = new Map<\n State.Extends,\n Set<[Expect, boolean | undefined]> | null\n >();\n public provide = new Map<State.Extends, Set<[State, boolean]> | null>();\n\n protected inputs: Record<string | number, State | State.Extends> = {};\n\n private cleanup = new Map<string | number | Function, () => void>();\n\n constructor(arg?: Context | Accept) {\n if (arg instanceof Context) {\n this.parent = arg;\n arg.scope.add(this);\n } else if (arg) {\n this.set(arg);\n }\n }\n\n private traverse(accept: (ctx: Context) => boolean | void) {\n const queue = [...this.scope];\n for (const ctx of queue)\n if (accept(ctx) !== false) for (const c of ctx.scope) queue.push(c);\n }\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [Expect<T>, boolean | undefined],\n asConsumer: true,\n ): () => void;\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [T, boolean],\n asConsumer?: false,\n ): () => void;\n\n private register(type: State.Extends, value: any, asConsumer?: boolean) {\n const mode = asConsumer ? \"consume\" : \"provide\";\n let set = this[mode].get(type) as Set<any>;\n if (!set) this[mode].set(type, (set = new Set()));\n set.add(value);\n\n for (let ctx = this.parent; ctx; ctx = ctx.parent) {\n if (ctx[mode].has(type)) break;\n ctx[mode].set(type, null);\n }\n\n return () => set.delete(value);\n }\n\n /** Find specified type upstream. Throws if not found. */\n public get<T extends State>(Type: State.Extends<T>, required?: true): T;\n\n /** Find specified type upstream. Returns undefined if not found. */\n public get<T extends State>(\n Type: State.Extends<T>,\n required?: boolean,\n ): T | undefined;\n\n /** Subscribe to a type becoming available in context. */\n public get<T extends State>(\n Type: State.Extends<T>,\n callback: Expect<T>,\n downstream?: boolean,\n ): () => void;\n\n /** Lookup excluding a specific instance (used by State.prototype.get for upstream-of-self semantics). */\n public get<T extends State>(\n Type: State.Extends<T>,\n arg: boolean | Expect<T> | undefined,\n downstream: boolean | undefined,\n skip: State,\n ): T | undefined | (() => void);\n\n public get<T extends State>(\n Type: State.Extends<T>,\n arg?: boolean | Expect<T>,\n downstream?: boolean,\n skip?: State,\n ) {\n let found: T | null | undefined;\n let priority = false;\n\n for (let ctx: Context | undefined = this; ctx; ctx = ctx.parent) {\n const entries = ctx.provide.get(Type);\n if (!entries) continue;\n\n for (const [state, explicit] of entries) {\n if (state === skip || found === state) continue;\n if (!found || (explicit && !priority)) {\n found = state as T;\n priority = explicit;\n continue;\n }\n if (!priority) {\n found = null;\n break;\n }\n if (explicit)\n throw new Error(\n `Did find ${Type} in context, but multiple were defined.`,\n );\n }\n if (found !== undefined) break;\n }\n\n if (typeof arg === \"function\") {\n if (found && !downstream) arg(found, false);\n\n if (downstream !== false) {\n this.traverse((ctx) => {\n const has = ctx.provide.get(Type);\n if (has) for (const x of has) if (x[0] !== skip) arg(x[0] as T, true);\n return has !== undefined;\n });\n }\n\n return this.register(Type, [arg as Expect, downstream], true);\n }\n\n if (found) return found;\n if (found === null) return null;\n if (arg !== false) throw new Error(`Could not find ${Type} in context.`);\n }\n\n /**\n * Register one or more States to this context.\n *\n * Context will add or remove States as needed to keep with provided input.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n * @param forEach Optional callback to run for each State registered. Receives\n * whether this context created the State - and so will destroy it - as\n * opposed to it having been provided already active. May return a callback\n * to run before that entry is dropped.\n */\n public set<T extends State>(\n inputs: Accept<T>,\n forEach?: (state: T, owned: boolean) => (() => void) | void,\n ) {\n const init = new Set<() => void>();\n const { cleanup } = this;\n\n if (typeof inputs == \"function\" || inputs instanceof State)\n inputs = { [0]: inputs };\n\n for (const K of Object.keys({ ...this.inputs, ...inputs })) {\n const V = inputs[K];\n const E = this.inputs[K];\n\n if (E === V) continue;\n\n if (E) {\n cleanup.get(K)?.();\n cleanup.delete(K);\n }\n\n if (!V) continue;\n\n // a class is constructed here - and so destroyed here; an instance is\n // adopted as-is and outlives this context\n const owned = State.is(V);\n\n if (!(owned || V instanceof State)) {\n const as = K == \"0\" || K == String(V) ? V : `${V} (as '${K}')`;\n throw new Error(\n `Context can only include an instance or class of State but got ${as}.`,\n );\n }\n\n const state = owned ? new (V as State.Type)() : V.is;\n const remove = this.add(state, true);\n\n init.add(() => {\n event(state);\n const dispose = forEach?.(state as T, owned);\n cleanup.set(K, () => {\n if (typeof dispose == \"function\") dispose();\n remove();\n if (owned) event(state, null);\n });\n });\n }\n\n for (const i of init) i();\n\n this.inputs = inputs;\n\n return this;\n }\n\n add(I: State, explicit = false) {\n const { cleanup, provide } = this;\n const root = this === Context.root;\n const TT: State.Extends[] = [];\n\n function conflict(T: State.Extends) {\n const entries = provide.get(T);\n if (entries)\n for (const entry of entries)\n if (!entry[1] && entry[0] !== I) {\n const type = I.constructor as State.Extends;\n const g = type.global;\n\n if (entry[0].constructor === type && (typeof g == 'function' ? g(I) : g))\n throw new Error(\n `Cannot register ${I} as a global - ${entry[0]} already exists in root. Destroy the existing instance first, or provide additional ones via explicit context.`\n );\n\n return entries.delete(entry);\n }\n }\n\n for (\n let T = I.constructor as State.Extends;\n T !== State;\n T = Object.getPrototypeOf(T)\n )\n if (explicit || !root || !conflict(T)) TT.push(T);\n\n const expects = new Map<Expect, () => void>();\n const onDone = new Set<() => void>();\n\n for (const T of TT) onDone.add(this.register(T, [I, explicit]));\n\n function queue(ctx: Context, downstream: boolean, same?: boolean) {\n let found = false;\n for (const T of TT) {\n const list = ctx.consume.get(T);\n if (list !== undefined) found = true;\n if (list)\n for (const [cb, filter] of list)\n if (same || filter == null || filter === downstream)\n expects.set(cb, () => {\n const r = cb(I, filter ?? downstream);\n if (r) onDone.add(r);\n });\n }\n return found;\n }\n\n queue(this, true, true);\n for (let ctx = this.parent; ctx; ctx = ctx.parent) queue(ctx, true);\n this.traverse((ctx) => queue(ctx, false));\n\n if (!LOOKUP.has(I)) LOOKUP.set(I, this);\n\n listener(I, () => {\n expects.forEach((f) => f());\n expects.clear();\n return null;\n });\n\n function flush() {\n onDone.forEach((r) => r());\n onDone.clear();\n }\n\n function remove() {\n cleanup.delete(remove);\n flush();\n }\n\n cleanup.set(remove, remove);\n\n return remove;\n }\n\n /**\n * Create a child context, optionally registering one or more States to it.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n */\n public push(inputs?: Accept) {\n const next = new Context(this);\n if (inputs) next.set(inputs);\n return next;\n }\n\n /**\n * Remove all States from this context.\n *\n * Will also run any cleanup callbacks registered when States were added.\n */\n public pop() {\n this.inputs = {};\n this.scope.forEach((x) => x.pop());\n this.scope.clear();\n this.cleanup.forEach((cb) => cb());\n this.cleanup.clear();\n this.consume.clear();\n this.provide.clear();\n if (this.parent) {\n this.parent.scope.delete(this);\n }\n }\n}\n\nObject.defineProperty(Context.prototype, \"toString\", {\n value() {\n return `Context-${this.id}`;\n },\n});\n\nexport { Context };\n"],"mappings":"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"}
1
+ {"version":3,"file":"context.js","names":[],"sources":["../src/context.ts"],"sourcesContent":["import { listener } from \"./observable\";\nimport { event, State, uid } from \"./state\";\n\nconst LOOKUP = new WeakMap<State, Context>();\nconst HELD = new WeakMap<State, Set<State>>();\nlet ROOT: Context;\n\ntype Accept<T extends State = State> =\n | T\n | State.Type<T>\n | Record<string | number, T | State.Type<T>>;\n\ntype Expect<T extends State = State> = (\n state: T,\n downstream: boolean,\n) => (() => void) | void;\n\ndeclare namespace Context {\n export { Accept, Expect };\n}\n\nclass Context {\n static get root(): Context {\n return ROOT ??= new Context();\n }\n\n /** Get the context for a State. Adapters may override to provide framework context. */\n static get(state?: State): Context {\n return state && LOOKUP.get(state.is) || Context.root;\n }\n\n public id = uid();\n public parent?: Context;\n public scope = new Set<Context>();\n public consume = new Map<\n State.Extends,\n Set<[Expect, boolean | undefined]> | null\n >();\n public provide = new Map<State.Extends, Set<[State, boolean]> | null>();\n\n protected inputs: Record<string | number, State | State.Extends> = {};\n\n private cleanup = new Map<string | number | Function, () => void>();\n\n constructor(arg?: Context | Accept) {\n if (arg instanceof Context) {\n this.parent = arg;\n arg.scope.add(this);\n } else if (arg) {\n this.set(arg);\n }\n }\n\n private traverse(accept: (ctx: Context) => boolean | void) {\n const queue = [...this.scope];\n for (const ctx of queue)\n if (accept(ctx) !== false) for (const c of ctx.scope) queue.push(c);\n }\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [Expect<T>, boolean | undefined],\n asConsumer: true,\n ): () => void;\n\n private register<T extends State>(\n type: State.Extends<T>,\n value: [T, boolean],\n asConsumer?: false,\n ): () => void;\n\n private register(type: State.Extends, value: any, asConsumer?: boolean) {\n const mode = asConsumer ? \"consume\" : \"provide\";\n let set = this[mode].get(type) as Set<any>;\n if (!set) this[mode].set(type, (set = new Set()));\n set.add(value);\n\n for (let ctx = this.parent; ctx; ctx = ctx.parent) {\n if (ctx[mode].has(type)) break;\n ctx[mode].set(type, null);\n }\n\n return () => set.delete(value);\n }\n\n /** Find specified type upstream. Throws if not found. */\n public get<T extends State>(Type: State.Extends<T>, required?: true): T;\n\n /** Find specified type upstream. Returns undefined if not found. */\n public get<T extends State>(\n Type: State.Extends<T>,\n required?: boolean,\n ): T | undefined;\n\n /** Subscribe to a type becoming available in context. */\n public get<T extends State>(\n Type: State.Extends<T>,\n callback: Expect<T>,\n downstream?: boolean,\n ): () => void;\n\n /** Lookup excluding a specific instance (used by State.prototype.get for upstream-of-self semantics). */\n public get<T extends State>(\n Type: State.Extends<T>,\n arg: boolean | Expect<T> | undefined,\n downstream: boolean | undefined,\n skip: State,\n ): T | undefined | (() => void);\n\n public get<T extends State>(\n Type: State.Extends<T>,\n arg?: boolean | Expect<T>,\n downstream?: boolean,\n skip?: State,\n ) {\n let found: T | null | undefined;\n let priority = false;\n\n for (let ctx: Context | undefined = this; ctx; ctx = ctx.parent) {\n const entries = ctx.provide.get(Type);\n if (!entries) continue;\n\n for (const [state, explicit] of entries) {\n if (state === skip || found === state) continue;\n if (!found || (explicit && !priority)) {\n found = state as T;\n priority = explicit;\n continue;\n }\n if (!priority) {\n found = null;\n break;\n }\n if (explicit)\n throw new Error(\n `Did find ${Type} in context, but multiple were defined.`,\n );\n }\n if (found !== undefined) break;\n }\n\n if (typeof arg === \"function\") {\n if (found && !downstream) arg(found, false);\n\n if (downstream !== false) {\n this.traverse((ctx) => {\n const has = ctx.provide.get(Type);\n if (has) for (const x of has) if (x[0] !== skip) arg(x[0] as T, true);\n return has !== undefined;\n });\n }\n\n return this.register(Type, [arg as Expect, downstream], true);\n }\n\n if (found) return found;\n if (found === null) return null;\n if (arg !== false) throw new Error(`Could not find ${Type} in context.`);\n }\n\n /**\n * Register one or more States to this context.\n *\n * Context will add or remove States as needed to keep with provided input.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n * @param forEach Optional callback to run for each State registered. Receives\n * whether this context created the State - and so will destroy it - as\n * opposed to it having been provided already active. May return a callback\n * to run before that entry is dropped.\n */\n public set<T extends State>(\n inputs: Accept<T>,\n forEach?: (state: T, owned: boolean) => (() => void) | void,\n ) {\n const init = new Set<() => void>();\n const { cleanup } = this;\n\n if (typeof inputs == \"function\" || inputs instanceof State)\n inputs = { [0]: inputs };\n\n for (const K of Object.keys({ ...this.inputs, ...inputs })) {\n const V = inputs[K];\n const E = this.inputs[K];\n\n if (E === V) continue;\n\n if (E) {\n cleanup.get(K)?.();\n cleanup.delete(K);\n }\n\n if (!V) continue;\n\n // a class is constructed here - and so destroyed here; an instance is\n // adopted as-is and outlives this context\n const owned = State.is(V);\n\n if (!(owned || V instanceof State)) {\n const as = K == \"0\" || K == String(V) ? V : `${V} (as '${K}')`;\n throw new Error(\n `Context can only include an instance or class of State but got ${as}.`,\n );\n }\n\n const state = owned ? new (V as State.Type)() : V.is;\n const remove = this.add(state, true);\n\n init.add(() => {\n event(state);\n const dispose = forEach?.(state as T, owned);\n cleanup.set(K, () => {\n if (typeof dispose == \"function\") dispose();\n remove();\n if (owned) event(state, null);\n });\n });\n }\n\n for (const i of init) i();\n\n this.inputs = inputs;\n\n return this;\n }\n\n add(I: State, explicit = false) {\n const { cleanup, provide } = this;\n const root = this === Context.root;\n const TT: State.Extends[] = [];\n\n function conflict(T: State.Extends) {\n const entries = provide.get(T);\n if (entries)\n for (const entry of entries)\n if (!entry[1] && entry[0] !== I) {\n const type = I.constructor as State.Extends;\n const g = type.global;\n\n if (entry[0].constructor === type && (typeof g == 'function' ? g(I) : g))\n throw new Error(\n `Cannot register ${I} as a global - ${entry[0]} already exists in root. Destroy the existing instance first, or provide additional ones via explicit context.`\n );\n\n return entries.delete(entry);\n }\n }\n\n for (\n let T = I.constructor as State.Extends;\n T !== State;\n T = Object.getPrototypeOf(T)\n )\n if (explicit || !root || !conflict(T)) TT.push(T);\n\n const expects = new Map<Expect, () => void>();\n const onDone = new Set<() => void>();\n\n for (const T of TT) onDone.add(this.register(T, [I, explicit]));\n\n function queue(ctx: Context, downstream: boolean, same?: boolean) {\n let found = false;\n for (const T of TT) {\n const list = ctx.consume.get(T);\n if (list !== undefined) found = true;\n if (list)\n for (const [cb, filter] of list)\n if (same || filter == null || filter === downstream)\n expects.set(cb, () => {\n const r = cb(I, filter ?? downstream);\n if (r) onDone.add(r);\n });\n }\n return found;\n }\n\n queue(this, true, true);\n for (let ctx = this.parent; ctx; ctx = ctx.parent) queue(ctx, true);\n this.traverse((ctx) => queue(ctx, false));\n\n if (!LOOKUP.has(I)) LOOKUP.set(I, this);\n\n listener(I, () => {\n expects.forEach((f) => f());\n expects.clear();\n return null;\n });\n\n function flush() {\n onDone.forEach((r) => r());\n onDone.clear();\n }\n\n const held = Array.from(HELD.get(I) || [], (child) => this.add(child));\n\n function remove() {\n cleanup.delete(remove);\n held.forEach((done) => done());\n flush();\n }\n\n cleanup.set(remove, remove);\n\n return remove;\n }\n\n /**\n * Create a child context, optionally registering one or more States to it.\n *\n * @param inputs State, State class, or map of States / State classes to register.\n */\n public push(inputs?: Accept) {\n const next = new Context(this);\n if (inputs) next.set(inputs);\n return next;\n }\n\n /**\n * Remove all States from this context.\n *\n * Will also run any cleanup callbacks registered when States were added.\n */\n public pop() {\n this.inputs = {};\n this.scope.forEach((x) => x.pop());\n this.scope.clear();\n this.cleanup.forEach((cb) => cb());\n this.cleanup.clear();\n this.consume.clear();\n this.provide.clear();\n if (this.parent) {\n this.parent.scope.delete(this);\n }\n }\n}\n\nObject.defineProperty(Context.prototype, \"toString\", {\n value() {\n return `Context-${this.id}`;\n },\n});\n\n/**\n * Add `value` to the context `state` was added to. A context-less `state` holds\n * it instead - every context adding `state` later adds its held children too.\n */\nfunction join(state: State, value: State): () => void {\n const ctx = LOOKUP.get(state.is);\n\n if (ctx) return ctx.add(value);\n\n const held = HELD.get(state) || new Set();\n HELD.set(state, held.add(value));\n\n return () => held.delete(value);\n}\n\nexport { Context, join };\n"],"mappings":";;;;AAGA,MAAM,yBAAS,IAAI,SAAyB;AAC5C,MAAM,uBAAO,IAAI,SAA4B;AAC7C,IAAI;AAgBJ,IAAM,UAAN,MAAM,QAAQ;CACZ,WAAW,OAAgB;AACzB,SAAO,SAAS,IAAI,SAAS;;;CAI/B,OAAO,IAAI,OAAwB;AACjC,SAAO,SAAS,OAAO,IAAI,MAAM,GAAG,IAAI,QAAQ;;CAGlD,AAAO,KAAK,KAAK;CACjB,AAAO;CACP,AAAO,wBAAQ,IAAI,KAAc;CACjC,AAAO,0BAAU,IAAI,KAGlB;CACH,AAAO,0BAAU,IAAI,KAAkD;CAEvE,AAAU,SAAyD,EAAE;CAErE,AAAQ,0BAAU,IAAI,KAA6C;CAEnE,YAAY,KAAwB;AAClC,MAAI,eAAe,SAAS;AAC1B,QAAK,SAAS;AACd,OAAI,MAAM,IAAI,KAAK;aACV,IACT,MAAK,IAAI,IAAI;;CAIjB,AAAQ,SAAS,QAA0C;EACzD,MAAM,QAAQ,CAAC,GAAG,KAAK,MAAM;AAC7B,OAAK,MAAM,OAAO,MAChB,KAAI,OAAO,IAAI,KAAK,MAAO,MAAK,MAAM,KAAK,IAAI,MAAO,OAAM,KAAK,EAAE;;CAevE,AAAQ,SAAS,MAAqB,OAAY,YAAsB;EACtE,MAAM,OAAO,aAAa,YAAY;EACtC,IAAI,MAAM,KAAK,MAAM,IAAI,KAAK;AAC9B,MAAI,CAAC,IAAK,MAAK,MAAM,IAAI,MAAO,sBAAM,IAAI,KAAK,CAAE;AACjD,MAAI,IAAI,MAAM;AAEd,OAAK,IAAI,MAAM,KAAK,QAAQ,KAAK,MAAM,IAAI,QAAQ;AACjD,OAAI,IAAI,MAAM,IAAI,KAAK,CAAE;AACzB,OAAI,MAAM,IAAI,MAAM,KAAK;;AAG3B,eAAa,IAAI,OAAO,MAAM;;CA2BhC,AAAO,IACL,MACA,KACA,YACA,MACA;EACA,IAAI;EACJ,IAAI,WAAW;AAEf,OAAK,IAAI,MAA2B,MAAM,KAAK,MAAM,IAAI,QAAQ;GAC/D,MAAM,UAAU,IAAI,QAAQ,IAAI,KAAK;AACrC,OAAI,CAAC,QAAS;AAEd,QAAK,MAAM,CAAC,OAAO,aAAa,SAAS;AACvC,QAAI,UAAU,QAAQ,UAAU,MAAO;AACvC,QAAI,CAAC,SAAU,YAAY,CAAC,UAAW;AACrC,aAAQ;AACR,gBAAW;AACX;;AAEF,QAAI,CAAC,UAAU;AACb,aAAQ;AACR;;AAEF,QAAI,SACF,OAAM,IAAI,MACR,YAAY,KAAK,yCAClB;;AAEL,OAAI,UAAU,OAAW;;AAG3B,MAAI,OAAO,QAAQ,YAAY;AAC7B,OAAI,SAAS,CAAC,WAAY,KAAI,OAAO,MAAM;AAE3C,OAAI,eAAe,MACjB,MAAK,UAAU,QAAQ;IACrB,MAAM,MAAM,IAAI,QAAQ,IAAI,KAAK;AACjC,QAAI,KAAK;UAAK,MAAM,KAAK,IAAK,KAAI,EAAE,OAAO,KAAM,KAAI,EAAE,IAAS,KAAK;;AACrE,WAAO,QAAQ;KACf;AAGJ,UAAO,KAAK,SAAS,MAAM,CAAC,KAAe,WAAW,EAAE,KAAK;;AAG/D,MAAI,MAAO,QAAO;AAClB,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,QAAQ,MAAO,OAAM,IAAI,MAAM,kBAAkB,KAAK,cAAc;;;;;;;;;;;;;CAc1E,AAAO,IACL,QACA,SACA;EACA,MAAM,uBAAO,IAAI,KAAiB;EAClC,MAAM,EAAE,YAAY;AAEpB,MAAI,OAAO,UAAU,cAAc,kBAAkB,MACnD,UAAS,GAAG,IAAI,QAAQ;AAE1B,OAAK,MAAM,KAAK,OAAO,KAAK;GAAE,GAAG,KAAK;GAAQ,GAAG;GAAQ,CAAC,EAAE;GAC1D,MAAM,IAAI,OAAO;GACjB,MAAM,IAAI,KAAK,OAAO;AAEtB,OAAI,MAAM,EAAG;AAEb,OAAI,GAAG;AACL,YAAQ,IAAI,EAAE,IAAI;AAClB,YAAQ,OAAO,EAAE;;AAGnB,OAAI,CAAC,EAAG;GAIR,MAAM,QAAQ,MAAM,GAAG,EAAE;AAEzB,OAAI,EAAE,SAAS,aAAa,QAAQ;IAClC,MAAM,KAAK,KAAK,OAAO,KAAK,OAAO,EAAE,GAAG,IAAI,GAAG,EAAE,QAAQ,EAAE;AAC3D,UAAM,IAAI,MACR,kEAAkE,GAAG,GACtE;;GAGH,MAAM,QAAQ,QAAQ,IAAK,GAAkB,GAAG,EAAE;GAClD,MAAM,SAAS,KAAK,IAAI,OAAO,KAAK;AAEpC,QAAK,UAAU;AACb,UAAM,MAAM;IACZ,MAAM,UAAU,UAAU,OAAY,MAAM;AAC5C,YAAQ,IAAI,SAAS;AACnB,SAAI,OAAO,WAAW,WAAY,UAAS;AAC3C,aAAQ;AACR,SAAI,MAAO,OAAM,OAAO,KAAK;MAC7B;KACF;;AAGJ,OAAK,MAAM,KAAK,KAAM,IAAG;AAEzB,OAAK,SAAS;AAEd,SAAO;;CAGT,IAAI,GAAU,WAAW,OAAO;EAC9B,MAAM,EAAE,SAAS,YAAY;EAC7B,MAAM,OAAO,SAAS,QAAQ;EAC9B,MAAM,KAAsB,EAAE;EAE9B,SAAS,SAAS,GAAkB;GAClC,MAAM,UAAU,QAAQ,IAAI,EAAE;AAC9B,OAAI,SACF;SAAK,MAAM,SAAS,QAClB,KAAI,CAAC,MAAM,MAAM,MAAM,OAAO,GAAG;KAC/B,MAAM,OAAO,EAAE;KACf,MAAM,IAAI,KAAK;AAEf,SAAI,MAAM,GAAG,gBAAgB,SAAS,OAAO,KAAK,aAAa,EAAE,EAAE,GAAG,GACpE,OAAM,IAAI,MACR,mBAAmB,EAAE,iBAAiB,MAAM,GAAG,gHAChD;AAEH,YAAO,QAAQ,OAAO,MAAM;;;;AAIpC,OACE,IAAI,IAAI,EAAE,aACV,MAAM,OACN,IAAI,OAAO,eAAe,EAAE,CAE5B,KAAI,YAAY,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAE,IAAG,KAAK,EAAE;EAEnD,MAAM,0BAAU,IAAI,KAAyB;EAC7C,MAAM,yBAAS,IAAI,KAAiB;AAEpC,OAAK,MAAM,KAAK,GAAI,QAAO,IAAI,KAAK,SAAS,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;EAE/D,SAAS,MAAM,KAAc,YAAqB,MAAgB;GAChE,IAAI,QAAQ;AACZ,QAAK,MAAM,KAAK,IAAI;IAClB,MAAM,OAAO,IAAI,QAAQ,IAAI,EAAE;AAC/B,QAAI,SAAS,OAAW,SAAQ;AAChC,QAAI,MACF;UAAK,MAAM,CAAC,IAAI,WAAW,KACzB,KAAI,QAAQ,UAAU,QAAQ,WAAW,WACvC,SAAQ,IAAI,UAAU;MACpB,MAAM,IAAI,GAAG,GAAG,UAAU,WAAW;AACrC,UAAI,EAAG,QAAO,IAAI,EAAE;OACpB;;;AAEV,UAAO;;AAGT,QAAM,MAAM,MAAM,KAAK;AACvB,OAAK,IAAI,MAAM,KAAK,QAAQ,KAAK,MAAM,IAAI,OAAQ,OAAM,KAAK,KAAK;AACnE,OAAK,UAAU,QAAQ,MAAM,KAAK,MAAM,CAAC;AAEzC,MAAI,CAAC,OAAO,IAAI,EAAE,CAAE,QAAO,IAAI,GAAG,KAAK;AAEvC,WAAS,SAAS;AAChB,WAAQ,SAAS,MAAM,GAAG,CAAC;AAC3B,WAAQ,OAAO;AACf,UAAO;IACP;EAEF,SAAS,QAAQ;AACf,UAAO,SAAS,MAAM,GAAG,CAAC;AAC1B,UAAO,OAAO;;EAGhB,MAAM,OAAO,MAAM,KAAK,KAAK,IAAI,EAAE,IAAI,EAAE,GAAG,UAAU,KAAK,IAAI,MAAM,CAAC;EAEtE,SAAS,SAAS;AAChB,WAAQ,OAAO,OAAO;AACtB,QAAK,SAAS,SAAS,MAAM,CAAC;AAC9B,UAAO;;AAGT,UAAQ,IAAI,QAAQ,OAAO;AAE3B,SAAO;;;;;;;CAQT,AAAO,KAAK,QAAiB;EAC3B,MAAM,OAAO,IAAI,QAAQ,KAAK;AAC9B,MAAI,OAAQ,MAAK,IAAI,OAAO;AAC5B,SAAO;;;;;;;CAQT,AAAO,MAAM;AACX,OAAK,SAAS,EAAE;AAChB,OAAK,MAAM,SAAS,MAAM,EAAE,KAAK,CAAC;AAClC,OAAK,MAAM,OAAO;AAClB,OAAK,QAAQ,SAAS,OAAO,IAAI,CAAC;AAClC,OAAK,QAAQ,OAAO;AACpB,OAAK,QAAQ,OAAO;AACpB,OAAK,QAAQ,OAAO;AACpB,MAAI,KAAK,OACP,MAAK,OAAO,MAAM,OAAO,KAAK;;;AAKpC,OAAO,eAAe,QAAQ,WAAW,YAAY,EACnD,QAAQ;AACN,QAAO,WAAW,KAAK;GAE1B,CAAC;;;;;AAMF,SAAS,KAAK,OAAc,OAA0B;CACpD,MAAM,MAAM,OAAO,IAAI,MAAM,GAAG;AAEhC,KAAI,IAAK,QAAO,IAAI,IAAI,MAAM;CAE9B,MAAM,OAAO,KAAK,IAAI,MAAM,oBAAI,IAAI,KAAK;AACzC,MAAK,IAAI,OAAO,KAAK,IAAI,MAAM,CAAC;AAEhC,cAAa,KAAK,OAAO,MAAM"}
@@ -1,8 +1,37 @@
1
1
  //#region src/dispatch.d.ts
2
2
  type Handler = () => void;
3
3
  type Transition = (work: Handler) => void;
4
- declare function enqueue(handler: Handler): void;
5
- declare function schedule(work: Handler, transition?: Transition): void;
4
+ type Hold = (retry?: Handler | false) => void;
5
+ /**
6
+ * Hold the work being replayed until the returned callback runs - a subscriber
7
+ * which has not yet absorbed the update takes one, and settlement waits on it
8
+ * rather than on the replay. Returns nothing unless the replay carries pending
9
+ * work, so an unrelated subscriber pays for none of it.
10
+ */
11
+ declare function hold(detached?: true, transition?: Transition): Hold | undefined;
12
+ /**
13
+ * Queue `handler` to replay after this tick. `transition` is how this
14
+ * subscriber defers - it brackets the replay, but only where the scheduled
15
+ * work asked for one.
16
+ */
17
+ declare function enqueue(handler: Handler, transition?: Transition): void;
18
+ /**
19
+ * Run `work` now, marking the subscriber updates it queues non-urgent - each
20
+ * replays through whatever scheduler it subscribed with. The callback itself is
21
+ * synchronous; only what it notifies is pending.
22
+ *
23
+ * Resolves once every one of those updates has replayed and been absorbed. A
24
+ * subscriber which cannot report absorption resolves on replay; one which can
25
+ * defer brackets its own replay.
26
+ */
27
+ declare function pending(work: Handler): Promise<void>;
28
+ /**
29
+ * Declare the subscriber currently replaying has not absorbed its update yet -
30
+ * settlement waits on the returned callback rather than on the replay. Call
31
+ * only from inside a replay carrying pending work; elsewhere this returns
32
+ * nothing and the subscriber pays for none of it.
33
+ */
34
+ declare function pending(): (() => void) | undefined;
6
35
  //#endregion
7
- export { enqueue, schedule };
36
+ export { enqueue, hold, pending };
8
37
  //# sourceMappingURL=dispatch.d.ts.map
package/dist/dispatch.js CHANGED
@@ -1,37 +1,101 @@
1
1
  //#region src/dispatch.ts
2
2
  const DISPATCH = /* @__PURE__ */ new Map();
3
- let active;
4
- function execute(work, transition) {
5
- if (!transition) return work();
6
- const parent = active;
7
- active = transition;
8
- try {
9
- transition(work);
10
- } finally {
11
- active = parent;
3
+ let current;
4
+ let replaying;
5
+ /**
6
+ * Await this handler's replay for the work being scheduled. Overlapping calls
7
+ * may each be waiting on the same handler, which replays once.
8
+ */
9
+ function claim(scheduled) {
10
+ if (!current) return;
11
+ const awaiting = scheduled.awaiting || (scheduled.awaiting = /* @__PURE__ */ new Set());
12
+ for (const record of current) if (!awaiting.has(record)) {
13
+ awaiting.add(record);
14
+ record.count++;
12
15
  }
13
16
  }
14
- function enqueue(handler) {
15
- if (!DISPATCH.size) queueMicrotask(() => {
16
- for (const [handler, scheduled] of DISPATCH) {
17
- DISPATCH.delete(handler);
18
- try {
19
- execute(handler, scheduled.transition);
20
- } catch (err) {
21
- console.error(err);
22
- }
17
+ function drop(scheduled) {
18
+ const { awaiting } = scheduled;
19
+ if (!awaiting) return;
20
+ scheduled.awaiting = void 0;
21
+ for (const record of awaiting) if (!--record.count) record.done();
22
+ }
23
+ /**
24
+ * Hold the work being replayed until the returned callback runs - a subscriber
25
+ * which has not yet absorbed the update takes one, and settlement waits on it
26
+ * rather than on the replay. Returns nothing unless the replay carries pending
27
+ * work, so an unrelated subscriber pays for none of it.
28
+ */
29
+ function hold(detached, transition) {
30
+ const scheduled = replaying || {};
31
+ if (detached) {
32
+ scheduled.transition = transition;
33
+ claim(scheduled);
34
+ } else if (!scheduled.awaiting) return;
35
+ let released = false;
36
+ scheduled.holds = (scheduled.holds || 0) + 1;
37
+ const release = (retry) => {
38
+ if (released) return;
39
+ if (retry === false) return claim(scheduled);
40
+ if (retry) {
41
+ current = scheduled.awaiting;
42
+ enqueue(retry, scheduled.transition);
43
+ current = void 0;
23
44
  }
24
- });
45
+ released = true;
46
+ if (!--scheduled.holds) drop(scheduled);
47
+ };
48
+ return release;
49
+ }
50
+ function flush() {
51
+ for (const [handler, scheduled] of DISPATCH) {
52
+ DISPATCH.delete(handler);
53
+ const { awaiting, transition } = scheduled;
54
+ current = awaiting;
55
+ replaying = scheduled;
56
+ try {
57
+ if (transition) transition(handler);
58
+ else handler();
59
+ } catch (err) {
60
+ console.error(err);
61
+ } finally {
62
+ current = replaying = void 0;
63
+ }
64
+ if (!scheduled.holds) drop(scheduled);
65
+ }
66
+ }
67
+ /**
68
+ * Queue `handler` to replay after this tick. `transition` is how this
69
+ * subscriber defers - it brackets the replay, but only where the scheduled
70
+ * work asked for one.
71
+ */
72
+ function enqueue(handler, transition) {
73
+ if (!DISPATCH.size) queueMicrotask(flush);
25
74
  const scheduled = DISPATCH.get(handler);
26
- if (scheduled) {
27
- if (!active) scheduled.transition = void 0;
28
- } else DISPATCH.set(handler, { transition: active });
75
+ if (!scheduled) {
76
+ const next = { transition: current ? transition : void 0 };
77
+ DISPATCH.set(handler, next);
78
+ claim(next);
79
+ } else if (current) claim(scheduled);
80
+ else scheduled.transition = void 0;
29
81
  }
30
- function schedule(work, transition) {
31
- if (!transition || transition === active) return work();
32
- execute(work, transition);
82
+ function pending(work) {
83
+ if (!work) return hold();
84
+ const parent = current;
85
+ const record = { count: 1 };
86
+ const promise = new Promise((resolve) => {
87
+ record.done = resolve;
88
+ });
89
+ current = parent ? [...parent, record] : [record];
90
+ try {
91
+ work();
92
+ } finally {
93
+ current = parent;
94
+ if (!--record.count) record.done();
95
+ }
96
+ return promise;
33
97
  }
34
98
 
35
99
  //#endregion
36
- export { enqueue, schedule };
100
+ export { enqueue, hold, pending };
37
101
  //# sourceMappingURL=dispatch.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dispatch.js","names":[],"sources":["../src/dispatch.ts"],"sourcesContent":["type Handler = () => void;\ntype Transition = (work: Handler) => void;\n\ninterface Scheduled {\n transition?: Transition;\n}\n\nconst DISPATCH = new Map<Handler, Scheduled>();\nlet active: Transition | undefined;\n\nfunction execute(work: Handler, transition?: Transition) {\n if (!transition) return work();\n\n const parent = active;\n active = transition;\n\n try {\n transition(work);\n } finally {\n active = parent;\n }\n}\n\nfunction enqueue(handler: Handler) {\n if (!DISPATCH.size)\n queueMicrotask(() => {\n for (const [handler, scheduled] of DISPATCH) {\n DISPATCH.delete(handler);\n\n try {\n execute(handler, scheduled.transition);\n } catch (err) {\n console.error(err);\n }\n }\n });\n\n const scheduled = DISPATCH.get(handler);\n\n if (scheduled) {\n if (!active) scheduled.transition = undefined;\n } else {\n DISPATCH.set(handler, { transition: active });\n }\n}\n\nfunction schedule(work: Handler, transition?: Transition) {\n if (!transition || transition === active) return work();\n execute(work, transition);\n}\n\nexport { enqueue, schedule };\n"],"mappings":";AAOA,MAAM,2BAAW,IAAI,KAAyB;AAC9C,IAAI;AAEJ,SAAS,QAAQ,MAAe,YAAyB;AACvD,KAAI,CAAC,WAAY,QAAO,MAAM;CAE9B,MAAM,SAAS;AACf,UAAS;AAET,KAAI;AACF,aAAW,KAAK;WACR;AACR,WAAS;;;AAIb,SAAS,QAAQ,SAAkB;AACjC,KAAI,CAAC,SAAS,KACZ,sBAAqB;AACnB,OAAK,MAAM,CAAC,SAAS,cAAc,UAAU;AAC3C,YAAS,OAAO,QAAQ;AAExB,OAAI;AACF,YAAQ,SAAS,UAAU,WAAW;YAC/B,KAAK;AACZ,YAAQ,MAAM,IAAI;;;GAGtB;CAEJ,MAAM,YAAY,SAAS,IAAI,QAAQ;AAEvC,KAAI,WACF;MAAI,CAAC,OAAQ,WAAU,aAAa;OAEpC,UAAS,IAAI,SAAS,EAAE,YAAY,QAAQ,CAAC;;AAIjD,SAAS,SAAS,MAAe,YAAyB;AACxD,KAAI,CAAC,cAAc,eAAe,OAAQ,QAAO,MAAM;AACvD,SAAQ,MAAM,WAAW"}
1
+ {"version":3,"file":"dispatch.js","names":[],"sources":["../src/dispatch.ts"],"sourcesContent":["type Handler = () => void;\ntype Transition = (work: Handler) => void;\n\ninterface Pending {\n count: number;\n done(): void;\n}\n\ntype Hold = (retry?: Handler | false) => void;\n\ninterface Scheduled {\n /** How this subscriber defers, if it can - supplied where it subscribed. */\n transition?: Transition;\n awaiting?: Set<Pending>;\n holds?: number;\n}\n\nconst DISPATCH = new Map<Handler, Scheduled>();\nlet current: Iterable<Pending> | undefined;\nlet replaying: Scheduled | undefined;\n\n/**\n * Await this handler's replay for the work being scheduled. Overlapping calls\n * may each be waiting on the same handler, which replays once.\n */\nfunction claim(scheduled: Scheduled) {\n if (!current) return;\n\n const awaiting = scheduled.awaiting || (scheduled.awaiting = new Set());\n\n for (const record of current)\n if (!awaiting.has(record)) {\n awaiting.add(record);\n record.count++;\n }\n}\n\nfunction drop(scheduled: Scheduled) {\n const { awaiting } = scheduled;\n\n if (!awaiting) return;\n\n scheduled.awaiting = undefined;\n\n for (const record of awaiting)\n if (!--record.count) record.done();\n}\n\n/**\n * Hold the work being replayed until the returned callback runs - a subscriber\n * which has not yet absorbed the update takes one, and settlement waits on it\n * rather than on the replay. Returns nothing unless the replay carries pending\n * work, so an unrelated subscriber pays for none of it.\n */\nfunction hold(detached?: true, transition?: Transition) {\n const scheduled = replaying || {};\n\n if (detached) {\n scheduled.transition = transition;\n claim(scheduled);\n }\n else if (!scheduled.awaiting) return;\n\n let released = false;\n\n scheduled.holds = (scheduled.holds || 0) + 1;\n\n const release: Hold = (retry) => {\n if (released) return;\n if (retry === false) return claim(scheduled);\n\n if (retry) {\n current = scheduled.awaiting;\n enqueue(retry, scheduled.transition);\n current = undefined;\n }\n\n released = true;\n if (!--scheduled.holds!) drop(scheduled);\n };\n\n return release;\n}\n\nfunction flush() {\n for (const [handler, scheduled] of DISPATCH) {\n DISPATCH.delete(handler);\n\n const { awaiting, transition } = scheduled;\n\n current = awaiting;\n replaying = scheduled;\n\n try {\n if (transition) transition(handler);\n else handler();\n } catch (err) {\n console.error(err);\n } finally {\n current = replaying = undefined;\n }\n\n if (!scheduled.holds) drop(scheduled);\n }\n}\n\n/**\n * Queue `handler` to replay after this tick. `transition` is how this\n * subscriber defers - it brackets the replay, but only where the scheduled\n * work asked for one.\n */\nfunction enqueue(handler: Handler, transition?: Transition) {\n if (!DISPATCH.size) queueMicrotask(flush);\n\n const scheduled = DISPATCH.get(handler);\n\n if (!scheduled) {\n const next: Scheduled = {\n transition: current ? transition : undefined\n };\n\n DISPATCH.set(handler, next);\n claim(next);\n } else if (current) {\n claim(scheduled);\n } else {\n scheduled.transition = undefined;\n }\n}\n\n/**\n * Run `work` now, marking the subscriber updates it queues non-urgent - each\n * replays through whatever scheduler it subscribed with. The callback itself is\n * synchronous; only what it notifies is pending.\n *\n * Resolves once every one of those updates has replayed and been absorbed. A\n * subscriber which cannot report absorption resolves on replay; one which can\n * defer brackets its own replay.\n */\nfunction pending(work: Handler): Promise<void>;\n\n/**\n * Declare the subscriber currently replaying has not absorbed its update yet -\n * settlement waits on the returned callback rather than on the replay. Call\n * only from inside a replay carrying pending work; elsewhere this returns\n * nothing and the subscriber pays for none of it.\n */\nfunction pending(): (() => void) | undefined;\n\nfunction pending(work?: Handler): Promise<void> | (() => void) | undefined {\n if (!work) return hold();\n\n const parent = current;\n const record = { count: 1 } as Pending;\n const promise = new Promise<void>((resolve) => {\n record.done = resolve;\n });\n\n current = parent ? [...parent, record] : [record];\n\n try {\n work();\n } finally {\n current = parent;\n if (!--record.count) record.done();\n }\n\n return promise;\n}\n\nexport { enqueue, hold, pending };\n"],"mappings":";AAiBA,MAAM,2BAAW,IAAI,KAAyB;AAC9C,IAAI;AACJ,IAAI;;;;;AAMJ,SAAS,MAAM,WAAsB;AACnC,KAAI,CAAC,QAAS;CAEd,MAAM,WAAW,UAAU,aAAa,UAAU,2BAAW,IAAI,KAAK;AAEtE,MAAK,MAAM,UAAU,QACnB,KAAI,CAAC,SAAS,IAAI,OAAO,EAAE;AACzB,WAAS,IAAI,OAAO;AACpB,SAAO;;;AAIb,SAAS,KAAK,WAAsB;CAClC,MAAM,EAAE,aAAa;AAErB,KAAI,CAAC,SAAU;AAEf,WAAU,WAAW;AAErB,MAAK,MAAM,UAAU,SACnB,KAAI,CAAC,EAAE,OAAO,MAAO,QAAO,MAAM;;;;;;;;AAStC,SAAS,KAAK,UAAiB,YAAyB;CACtD,MAAM,YAAY,aAAa,EAAE;AAEjC,KAAI,UAAU;AACZ,YAAU,aAAa;AACvB,QAAM,UAAU;YAET,CAAC,UAAU,SAAU;CAE9B,IAAI,WAAW;AAEf,WAAU,SAAS,UAAU,SAAS,KAAK;CAE3C,MAAM,WAAiB,UAAU;AAC/B,MAAI,SAAU;AACd,MAAI,UAAU,MAAO,QAAO,MAAM,UAAU;AAE5C,MAAI,OAAO;AACT,aAAU,UAAU;AACpB,WAAQ,OAAO,UAAU,WAAW;AACpC,aAAU;;AAGZ,aAAW;AACX,MAAI,CAAC,EAAE,UAAU,MAAQ,MAAK,UAAU;;AAG1C,QAAO;;AAGT,SAAS,QAAQ;AACf,MAAK,MAAM,CAAC,SAAS,cAAc,UAAU;AAC3C,WAAS,OAAO,QAAQ;EAExB,MAAM,EAAE,UAAU,eAAe;AAEjC,YAAU;AACV,cAAY;AAEZ,MAAI;AACF,OAAI,WAAY,YAAW,QAAQ;OAC9B,UAAS;WACP,KAAK;AACZ,WAAQ,MAAM,IAAI;YACV;AACR,aAAU,YAAY;;AAGxB,MAAI,CAAC,UAAU,MAAO,MAAK,UAAU;;;;;;;;AASzC,SAAS,QAAQ,SAAkB,YAAyB;AAC1D,KAAI,CAAC,SAAS,KAAM,gBAAe,MAAM;CAEzC,MAAM,YAAY,SAAS,IAAI,QAAQ;AAEvC,KAAI,CAAC,WAAW;EACd,MAAM,OAAkB,EACtB,YAAY,UAAU,aAAa,QACpC;AAED,WAAS,IAAI,SAAS,KAAK;AAC3B,QAAM,KAAK;YACF,QACT,OAAM,UAAU;KAEhB,WAAU,aAAa;;AAuB3B,SAAS,QAAQ,MAA0D;AACzE,KAAI,CAAC,KAAM,QAAO,MAAM;CAExB,MAAM,SAAS;CACf,MAAM,SAAS,EAAE,OAAO,GAAG;CAC3B,MAAM,UAAU,IAAI,SAAe,YAAY;AAC7C,SAAO,OAAO;GACd;AAEF,WAAU,SAAS,CAAC,GAAG,QAAQ,OAAO,GAAG,CAAC,OAAO;AAEjD,KAAI;AACF,QAAM;WACE;AACR,YAAU;AACV,MAAI,CAAC,EAAE,OAAO,MAAO,QAAO,MAAM;;AAGpC,QAAO"}
package/dist/field/set.js CHANGED
@@ -1,4 +1,4 @@
1
- import { capture, event, listener } from "../observable.js";
1
+ import { capture, event, listener, observer } from "../observable.js";
2
2
  import { access, compute, update } from "../state.js";
3
3
  import { def } from "./def.js";
4
4
 
@@ -31,7 +31,10 @@ function set(value, argument) {
31
31
  if (typeof argument == "function") subject[key] = next;
32
32
  else update(subject, key, next, silent, true);
33
33
  }
34
- if (output instanceof Promise) output.then(assign, (error) => {
34
+ if (output instanceof Promise) output.then((next) => {
35
+ if (observer(subject) !== null) assign(next);
36
+ }, (error) => {
37
+ if (observer(subject) === null) return;
35
38
  event(subject, key);
36
39
  config.get = () => {
37
40
  throw error;
@@ -1 +1 @@
1
- {"version":3,"file":"set.js","names":[],"sources":["../../src/field/set.ts"],"sourcesContent":["import { listener, capture } from '../observable';\nimport { access, compute, event, State, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace set {\n type Callback<T, S = any> = (\n this: S,\n next: T,\n previous: T\n ) => ((next: T) => void) | Promise<any> | void | boolean;\n\n type Factory<T, S = any> = (this: S, property: string) => Promise<T> | T;\n}\n\n/**\n * Set a property as a placeholder, initially `undefined` but required.\n *\n * Property cannot be accessed until it is defined. If accessed while undefined, a hybrid\n * `Promise`/`Error` (aka: [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html)) will be thrown.\n *\n * Non-enumerable; writable only if `onUpdate` callback is provided.\n *\n * @param value - Starting value (undefined for suspense placeholder).\n * @param onUpdate - Callback run when property is set.\n */\nfunction set<T>(value?: undefined, onUpdate?: set.Callback<T>): T;\n\n/**\n * Set property with an async factory function.\n * If required is not defined, factory runs lazily on first access.\n * If async, or returns a promise, suspense is thrown upon access until resolved.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg async callback to produce property value.\n * @param required - Pass `true` to run factory immediately and require value.\n */\nfunction set<T>(factory: () => T | Promise<T>, required?: true): T;\n\n/**\n * Set property with a lazy factory, no suspense.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg callback to produce property value.\n * @param required - Pass `false` to allow undefined while pending.\n */\nfunction set<T>(\n factory: () => T | Promise<T>,\n required: boolean\n): T | undefined;\n\n/**\n * Set property with a factory and update callback.\n *\n * Non-enumerable but writable via the callback.\n *\n * @param factory - Callback to produce initial value.\n * @param onUpdate - Callback run when property is updated.\n */\nfunction set<T>(factory: () => T | Promise<T>, onUpdate: set.Callback<T>): T;\n\n/**\n * Define a reactive computed property - the instruction equivalent of a getter.\n *\n * Unlike a zero-arg factory (which runs once and caches), the compute function\n * re-runs whenever any managed property it reads is updated. It receives the\n * instance as both `this` and its first argument, so arrow functions work.\n *\n * Enumerable and read-only, matching a prototype getter. Because it assigns\n * through an instruction rather than a concrete getter, subclasses may refine\n * the property's type with `declare`.\n *\n * @param compute - Function of arity >= 1; receives the instance to derive from.\n */\nfunction set<T, S = any>(compute: (this: S, self: S) => T): T;\n\n/**\n * Set a property with a non-function, non-Promise value.\n *\n * Non-enumerable but writable. Unlike plain assignment (`= value`), this\n * property is excluded from snapshots and `ref(this)`.\n *\n * @param value - Starting value for property.\n * @param onUpdate - Optional callback run when property is set.\n */\n// TODO: if onUpdate is not defined, should this have behavior unique to simple assignment?\n// I'm thinking default behavior should be to assign value directly to property, without triggering any additional updates.\n// All this requires is a default callback which throws true, silent updates are already implemented.\nfunction set<T>(\n value: T extends Promise<any> ? never : T,\n onUpdate?: set.Callback<T>\n): T;\n\nfunction set<T = any>(value?: unknown, argument?: unknown): any {\n return def<T>((key, subject) => {\n if (value instanceof Promise)\n throw new TypeError(\n `Direct promises are not supported in set(${subject}.${key}). Use set(() => promise) instead.`\n );\n\n if (typeof value == 'function' && value.length > 0) {\n compute.call(subject, value as () => unknown, key);\n return;\n }\n\n const config: State.Apply = {\n enumerable: false,\n set: false\n };\n\n let computed = false;\n\n // One-shot factory\n if (typeof value == 'function') {\n const factory = value.bind(subject, key)\n computed = true;\n\n function init() {\n let output: unknown;\n\n try {\n output = attempt(factory);\n } catch (err) {\n console.warn(\n `Generating initial value for ${subject}.${key} failed.`\n );\n throw err;\n }\n\n config.get = argument !== false;\n\n function assign(next: any, silent?: boolean) {\n if (typeof argument == 'function') subject[key] = next;\n else update(subject, key, next, silent, true);\n }\n\n if (output instanceof Promise)\n output.then(assign, (error) => {\n event(subject, key);\n config.get = () => {\n throw error;\n };\n });\n else assign(output, true);\n\n if (argument) return null;\n\n if (output instanceof Promise && argument !== false)\n return access(subject, key, true);\n\n return subject[key];\n }\n\n if (argument) {\n listener(subject, () => {\n init();\n return null;\n });\n } else {\n config.get = init;\n }\n } else if (value !== undefined) {\n config.value = value;\n }\n\n if (typeof argument == 'function') {\n let unset: ((next: T) => void) | undefined;\n\n config.set = function (this: any, value: any, previous: any) {\n capture((release) => {\n const returns = argument.call(this, value, previous);\n\n if (unset) unset(value);\n\n unset = (next: T) => {\n if (typeof returns == 'function') returns(next);\n release();\n };\n });\n };\n } else if (!computed)\n config.set = () => {\n config.get = undefined;\n config.set = undefined;\n };\n\n return config;\n });\n}\n\nfunction attempt(fn: () => any): any {\n function retry(err: unknown) {\n if (err instanceof Promise) return err.then(compute);\n else throw err;\n }\n\n function compute(): any {\n try {\n const output = fn();\n\n return output instanceof Promise ? output.catch(retry) : output;\n } catch (err) {\n return retry(err);\n }\n }\n\n return compute();\n}\n\nexport { set };\n"],"mappings":";;;;;AA8FA,SAAS,IAAa,OAAiB,UAAyB;AAC9D,QAAO,KAAQ,KAAK,YAAY;AAC9B,MAAI,iBAAiB,QACnB,OAAM,IAAI,UACR,4CAA4C,QAAQ,GAAG,IAAI,oCAC5D;AAEH,MAAI,OAAO,SAAS,cAAc,MAAM,SAAS,GAAG;AAClD,WAAQ,KAAK,SAAS,OAAwB,IAAI;AAClD;;EAGF,MAAM,SAAsB;GAC1B,YAAY;GACZ,KAAK;GACN;EAED,IAAI,WAAW;AAGf,MAAI,OAAO,SAAS,YAAY;GAC9B,MAAM,UAAU,MAAM,KAAK,SAAS,IAAI;AACxC,cAAW;GAEX,SAAS,OAAO;IACd,IAAI;AAEJ,QAAI;AACF,cAAS,QAAQ,QAAQ;aAClB,KAAK;AACZ,aAAQ,KACN,gCAAgC,QAAQ,GAAG,IAAI,UAChD;AACD,WAAM;;AAGR,WAAO,MAAM,aAAa;IAE1B,SAAS,OAAO,MAAW,QAAkB;AAC3C,SAAI,OAAO,YAAY,WAAY,SAAQ,OAAO;SAC7C,QAAO,SAAS,KAAK,MAAM,QAAQ,KAAK;;AAG/C,QAAI,kBAAkB,QACpB,QAAO,KAAK,SAAS,UAAU;AAC7B,WAAM,SAAS,IAAI;AACnB,YAAO,YAAY;AACjB,YAAM;;MAER;QACC,QAAO,QAAQ,KAAK;AAEzB,QAAI,SAAU,QAAO;AAErB,QAAI,kBAAkB,WAAW,aAAa,MAC5C,QAAO,OAAO,SAAS,KAAK,KAAK;AAEnC,WAAO,QAAQ;;AAGjB,OAAI,SACF,UAAS,eAAe;AACtB,UAAM;AACN,WAAO;KACP;OAEF,QAAO,MAAM;aAEN,UAAU,OACnB,QAAO,QAAQ;AAGjB,MAAI,OAAO,YAAY,YAAY;GACjC,IAAI;AAEJ,UAAO,MAAM,SAAqB,OAAY,UAAe;AAC3D,aAAS,YAAY;KACnB,MAAM,UAAU,SAAS,KAAK,MAAM,OAAO,SAAS;AAEpD,SAAI,MAAO,OAAM,MAAM;AAEvB,cAAS,SAAY;AACnB,UAAI,OAAO,WAAW,WAAY,SAAQ,KAAK;AAC/C,eAAS;;MAEX;;aAEK,CAAC,SACV,QAAO,YAAY;AACjB,UAAO,MAAM;AACb,UAAO,MAAM;;AAGjB,SAAO;GACP;;AAGJ,SAAS,QAAQ,IAAoB;CACnC,SAAS,MAAM,KAAc;AAC3B,MAAI,eAAe,QAAS,QAAO,IAAI,KAAK,QAAQ;MAC/C,OAAM;;CAGb,SAAS,UAAe;AACtB,MAAI;GACF,MAAM,SAAS,IAAI;AAEnB,UAAO,kBAAkB,UAAU,OAAO,MAAM,MAAM,GAAG;WAClD,KAAK;AACZ,UAAO,MAAM,IAAI;;;AAIrB,QAAO,SAAS"}
1
+ {"version":3,"file":"set.js","names":[],"sources":["../../src/field/set.ts"],"sourcesContent":["import { listener, capture, observer } from '../observable';\nimport { access, compute, event, State, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace set {\n type Callback<T, S = any> = (\n this: S,\n next: T,\n previous: T\n ) => ((next: T) => void) | Promise<any> | void | boolean;\n\n type Factory<T, S = any> = (this: S, property: string) => Promise<T> | T;\n}\n\n/**\n * Set a property as a placeholder, initially `undefined` but required.\n *\n * Property cannot be accessed until it is defined. If accessed while undefined, a hybrid\n * `Promise`/`Error` (aka: [Suspense](https://reactjs.org/docs/concurrent-mode-suspense.html)) will be thrown.\n *\n * Non-enumerable; writable only if `onUpdate` callback is provided.\n *\n * @param value - Starting value (undefined for suspense placeholder).\n * @param onUpdate - Callback run when property is set.\n */\nfunction set<T>(value?: undefined, onUpdate?: set.Callback<T>): T;\n\n/**\n * Set property with an async factory function.\n * If required is not defined, factory runs lazily on first access.\n * If async, or returns a promise, suspense is thrown upon access until resolved.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg async callback to produce property value.\n * @param required - Pass `true` to run factory immediately and require value.\n */\nfunction set<T>(factory: () => T | Promise<T>, required?: true): T;\n\n/**\n * Set property with a lazy factory, no suspense.\n *\n * Non-enumerable and read-only.\n *\n * @param factory - Zero-arg callback to produce property value.\n * @param required - Pass `false` to allow undefined while pending.\n */\nfunction set<T>(\n factory: () => T | Promise<T>,\n required: boolean\n): T | undefined;\n\n/**\n * Set property with a factory and update callback.\n *\n * Non-enumerable but writable via the callback.\n *\n * @param factory - Callback to produce initial value.\n * @param onUpdate - Callback run when property is updated.\n */\nfunction set<T>(factory: () => T | Promise<T>, onUpdate: set.Callback<T>): T;\n\n/**\n * Define a reactive computed property - the instruction equivalent of a getter.\n *\n * Unlike a zero-arg factory (which runs once and caches), the compute function\n * re-runs whenever any managed property it reads is updated. It receives the\n * instance as both `this` and its first argument, so arrow functions work.\n *\n * Enumerable and read-only, matching a prototype getter. Because it assigns\n * through an instruction rather than a concrete getter, subclasses may refine\n * the property's type with `declare`.\n *\n * @param compute - Function of arity >= 1; receives the instance to derive from.\n */\nfunction set<T, S = any>(compute: (this: S, self: S) => T): T;\n\n/**\n * Set a property with a non-function, non-Promise value.\n *\n * Non-enumerable but writable. Unlike plain assignment (`= value`), this\n * property is excluded from snapshots and `ref(this)`.\n *\n * @param value - Starting value for property.\n * @param onUpdate - Optional callback run when property is set.\n */\n// TODO: if onUpdate is not defined, should this have behavior unique to simple assignment?\n// I'm thinking default behavior should be to assign value directly to property, without triggering any additional updates.\n// All this requires is a default callback which throws true, silent updates are already implemented.\nfunction set<T>(\n value: T extends Promise<any> ? never : T,\n onUpdate?: set.Callback<T>\n): T;\n\nfunction set<T = any>(value?: unknown, argument?: unknown): any {\n return def<T>((key, subject) => {\n if (value instanceof Promise)\n throw new TypeError(\n `Direct promises are not supported in set(${subject}.${key}). Use set(() => promise) instead.`\n );\n\n if (typeof value == 'function' && value.length > 0) {\n compute.call(subject, value as () => unknown, key);\n return;\n }\n\n const config: State.Apply = {\n enumerable: false,\n set: false\n };\n\n let computed = false;\n\n // One-shot factory\n if (typeof value == 'function') {\n const factory = value.bind(subject, key)\n computed = true;\n\n function init() {\n let output: unknown;\n\n try {\n output = attempt(factory);\n } catch (err) {\n console.warn(\n `Generating initial value for ${subject}.${key} failed.`\n );\n throw err;\n }\n\n config.get = argument !== false;\n\n function assign(next: any, silent?: boolean) {\n if (typeof argument == 'function') subject[key] = next;\n else update(subject, key, next, silent, true);\n }\n\n if (output instanceof Promise)\n output.then((next) => {\n if (observer(subject) !== null) assign(next);\n }, (error) => {\n if (observer(subject) === null) return;\n event(subject, key);\n config.get = () => {\n throw error;\n };\n });\n else assign(output, true);\n\n if (argument) return null;\n\n if (output instanceof Promise && argument !== false)\n return access(subject, key, true);\n\n return subject[key];\n }\n\n if (argument) {\n listener(subject, () => {\n init();\n return null;\n });\n } else {\n config.get = init;\n }\n } else if (value !== undefined) {\n config.value = value;\n }\n\n if (typeof argument == 'function') {\n let unset: ((next: T) => void) | undefined;\n\n config.set = function (this: any, value: any, previous: any) {\n capture((release) => {\n const returns = argument.call(this, value, previous);\n\n if (unset) unset(value);\n\n unset = (next: T) => {\n if (typeof returns == 'function') returns(next);\n release();\n };\n });\n };\n } else if (!computed)\n config.set = () => {\n config.get = undefined;\n config.set = undefined;\n };\n\n return config;\n });\n}\n\nfunction attempt(fn: () => any): any {\n function retry(err: unknown) {\n if (err instanceof Promise) return err.then(compute);\n else throw err;\n }\n\n function compute(): any {\n try {\n const output = fn();\n\n return output instanceof Promise ? output.catch(retry) : output;\n } catch (err) {\n return retry(err);\n }\n }\n\n return compute();\n}\n\nexport { set };\n"],"mappings":";;;;;AA8FA,SAAS,IAAa,OAAiB,UAAyB;AAC9D,QAAO,KAAQ,KAAK,YAAY;AAC9B,MAAI,iBAAiB,QACnB,OAAM,IAAI,UACR,4CAA4C,QAAQ,GAAG,IAAI,oCAC5D;AAEH,MAAI,OAAO,SAAS,cAAc,MAAM,SAAS,GAAG;AAClD,WAAQ,KAAK,SAAS,OAAwB,IAAI;AAClD;;EAGF,MAAM,SAAsB;GAC1B,YAAY;GACZ,KAAK;GACN;EAED,IAAI,WAAW;AAGf,MAAI,OAAO,SAAS,YAAY;GAC9B,MAAM,UAAU,MAAM,KAAK,SAAS,IAAI;AACxC,cAAW;GAEX,SAAS,OAAO;IACd,IAAI;AAEJ,QAAI;AACF,cAAS,QAAQ,QAAQ;aAClB,KAAK;AACZ,aAAQ,KACN,gCAAgC,QAAQ,GAAG,IAAI,UAChD;AACD,WAAM;;AAGR,WAAO,MAAM,aAAa;IAE1B,SAAS,OAAO,MAAW,QAAkB;AAC3C,SAAI,OAAO,YAAY,WAAY,SAAQ,OAAO;SAC7C,QAAO,SAAS,KAAK,MAAM,QAAQ,KAAK;;AAG/C,QAAI,kBAAkB,QACpB,QAAO,MAAM,SAAS;AACpB,SAAI,SAAS,QAAQ,KAAK,KAAM,QAAO,KAAK;QAC1C,UAAU;AACZ,SAAI,SAAS,QAAQ,KAAK,KAAM;AAChC,WAAM,SAAS,IAAI;AACnB,YAAO,YAAY;AACjB,YAAM;;MAER;QACC,QAAO,QAAQ,KAAK;AAEzB,QAAI,SAAU,QAAO;AAErB,QAAI,kBAAkB,WAAW,aAAa,MAC5C,QAAO,OAAO,SAAS,KAAK,KAAK;AAEnC,WAAO,QAAQ;;AAGjB,OAAI,SACF,UAAS,eAAe;AACtB,UAAM;AACN,WAAO;KACP;OAEF,QAAO,MAAM;aAEN,UAAU,OACnB,QAAO,QAAQ;AAGjB,MAAI,OAAO,YAAY,YAAY;GACjC,IAAI;AAEJ,UAAO,MAAM,SAAqB,OAAY,UAAe;AAC3D,aAAS,YAAY;KACnB,MAAM,UAAU,SAAS,KAAK,MAAM,OAAO,SAAS;AAEpD,SAAI,MAAO,OAAM,MAAM;AAEvB,cAAS,SAAY;AACnB,UAAI,OAAO,WAAW,WAAY,SAAQ,KAAK;AAC/C,eAAS;;MAEX;;aAEK,CAAC,SACV,QAAO,YAAY;AACjB,UAAO,MAAM;AACb,UAAO,MAAM;;AAGjB,SAAO;GACP;;AAGJ,SAAS,QAAQ,IAAoB;CACnC,SAAS,MAAM,KAAc;AAC3B,MAAI,eAAe,QAAS,QAAO,IAAI,KAAK,QAAQ;MAC/C,OAAM;;CAGb,SAAS,UAAe;AACtB,MAAI;GACF,MAAM,SAAS,IAAI;AAEnB,UAAO,kBAAkB,UAAU,OAAO,MAAM,MAAM,GAAG;WAClD,KAAK;AACZ,UAAO,MAAM,IAAI;;;AAIrB,QAAO,SAAS"}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  import { Context } from "./context.js";
2
2
  import { State, unbind } from "./state.js";
3
- import { transition } from "./runtime.js";
4
3
  import { Component } from "./component.js";
4
+ import { pending } from "./dispatch.js";
5
5
  import { def } from "./field/def.js";
6
6
  import { get } from "./field/get.js";
7
7
  import { has } from "./field/has.js";
8
8
  import { map } from "./field/map.js";
9
9
  import { ref } from "./field/ref.js";
10
10
  import { set } from "./field/set.js";
11
- export { Component, Context, State, def, State as default, get, has, map, ref, set, transition, unbind };
11
+ export { Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { pending } from "./dispatch.js";
1
2
  import { State, unbind } from "./state.js";
2
3
  import { Context } from "./context.js";
3
4
  import { def } from "./field/def.js";
@@ -7,6 +8,5 @@ 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
- import { transition } from "./runtime.js";
11
11
 
12
- export { Component, Context, State, def, State as default, get, has, map, ref, set, transition, unbind };
12
+ export { Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
@@ -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 pending<K extends Observer.Event>(state: object): K[] & PromiseLike<K[]>;
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, pending, touch, watch };
57
+ export { Observer, capture, event, listener, observer, queued, touch, watch };
58
58
  //# sourceMappingURL=observable.d.ts.map
@@ -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");
@@ -22,8 +22,13 @@ function observer(state, create) {
22
22
  }
23
23
  function observe(object, callback, required) {
24
24
  const watching = /* @__PURE__ */ new Set();
25
+ const observing = {
26
+ callback,
27
+ watching,
28
+ required
29
+ };
25
30
  const release = listener(object, (key) => {
26
- if (watching.has(key)) return callback();
31
+ if (watching.has(key)) return observing.callback();
27
32
  });
28
33
  if (EffectContext) EffectContext.add((update) => {
29
34
  if (update !== true) release();
@@ -33,18 +38,14 @@ function observe(object, callback, required) {
33
38
  value: object.is,
34
39
  writable: true
35
40
  });
36
- return Object.defineProperty(proxy, Observing, { value: {
37
- callback,
38
- watching,
39
- required
40
- } });
41
+ return Object.defineProperty(proxy, Observing, { value: observing });
41
42
  }
42
43
  function touch(from, key, value) {
43
44
  const active = from[Observing];
44
45
  if (active) {
45
46
  if (value === void 0 && arguments.length === 3 && active.required) throw new Error(`${Object.getPrototypeOf(from)}.${String(key)} is required in this context.`);
46
47
  active.watching.add(key);
47
- if (value instanceof Object && observer(value)) return observe(value, active.callback, active.required);
48
+ if (value instanceof Object && observer(value)) return observe(value, () => active.callback(), active.required);
48
49
  }
49
50
  return value;
50
51
  }
@@ -56,7 +57,7 @@ function listener(subject, callback, select) {
56
57
  return () => o.listeners.delete(callback);
57
58
  }
58
59
  const EMPTY = Object.assign([], { then: Promise.prototype.then.bind(Promise.resolve([])) });
59
- function pending(state) {
60
+ function queued(state) {
60
61
  const o = observer(state);
61
62
  if (!o?.events.size) return EMPTY;
62
63
  const current = o.events;
@@ -103,29 +104,34 @@ function emit(o, key) {
103
104
  else if (key === true) o.ready = true;
104
105
  pending.clear();
105
106
  }
106
- function watch(target, callback, argument) {
107
+ function watch(target, callback, argument, transition) {
107
108
  const o = observer(target, true);
108
109
  let events = [];
109
110
  let unset;
110
111
  let reset;
111
112
  let previous;
112
113
  let queued = false;
114
+ let suspense;
115
+ function resume() {
116
+ suspense?.();
117
+ suspense = void 0;
118
+ }
113
119
  function invoke() {
114
- if (observer(target) === null) return;
120
+ if (reset === null || observer(target) === null) return;
115
121
  queued = false;
116
122
  let ignore = true;
117
123
  function onUpdate() {
118
124
  events = [...o.events];
119
125
  if (reset === null) return null;
120
126
  if (ignore) {
121
- if (queued) enqueue(invoke);
127
+ if (queued) enqueue(invoke, transition);
122
128
  return;
123
129
  }
124
130
  ignore = true;
125
131
  queued = true;
126
132
  unset(true);
127
133
  unset = void 0;
128
- enqueue(invoke);
134
+ enqueue(invoke, transition);
129
135
  }
130
136
  function run(release) {
131
137
  const proxy = observe(target, onUpdate, argument === true);
@@ -135,11 +141,8 @@ function watch(target, callback, argument) {
135
141
  if (release) release(null);
136
142
  return;
137
143
  }
138
- if (previous && argument === false) {
139
- const { watching } = proxy[Observing];
140
- if (!watching.size) previous[Observing].watching.forEach((k) => watching.add(k));
141
- }
142
- previous = proxy;
144
+ if (previous && argument === false && !proxy[Observing].watching.size) previous[Observing].callback = onUpdate;
145
+ else previous = proxy;
143
146
  ignore = false;
144
147
  reset = output === null ? null : invoke;
145
148
  unset = (key) => {
@@ -154,17 +157,30 @@ function watch(target, callback, argument) {
154
157
  } catch (err) {
155
158
  if (err instanceof Promise) {
156
159
  reset = void 0;
157
- err.then(invoke);
160
+ const suspended = suspense = hold(true, transition);
161
+ const replay = () => {
162
+ if (suspense !== suspended) return;
163
+ suspense = void 0;
164
+ suspended(invoke);
165
+ };
166
+ err.then(replay, replay);
158
167
  } else throw err;
159
168
  }
160
169
  }
161
170
  const unlisten = listener(target, (key) => {
162
171
  if (key === true) invoke();
163
- else if (!reset) return reset;
164
- if (key === null && unset) unset(null);
172
+ else if (key === null) {
173
+ if (unset) unset(null);
174
+ resume();
175
+ reset = null;
176
+ } else if (!reset) {
177
+ suspense?.(false);
178
+ return reset;
179
+ }
165
180
  });
166
181
  function cleanup() {
167
182
  if (unset) unset(false);
183
+ resume();
168
184
  reset = null;
169
185
  unlisten();
170
186
  }
@@ -183,5 +199,5 @@ function capture(scope) {
183
199
  }
184
200
 
185
201
  //#endregion
186
- export { Observer, capture, event, listener, observer, pending, touch, watch };
202
+ export { Observer, capture, event, listener, observer, queued, touch, watch };
187
203
  //# sourceMappingURL=observable.js.map
@@ -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}\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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"}
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 or scheduler seam).
54
- * Element mechanics the host leaves unset keep defaults that throw a
55
- * setup-pointing error; the optional seams (`jsxDEV`, `transition`) are
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, transition, typeOf };
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 or scheduler seam).
27
- * Element mechanics the host leaves unset keep defaults that throw a
28
- * setup-pointing error; the optional seams (`jsxDEV`, `transition`) are
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, transition, typeOf };
67
+ export { Fragment, childrenOf, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
79
68
  //# sourceMappingURL=runtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime.ts"],"sourcesContent":["import type { Component } from './component';\nimport { schedule } from './dispatch';\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 /** Non-urgent update bracket (e.g. React `startTransition`). Optional - see {@link transition}. */\n transition?(work: () => void): void;\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 or scheduler seam).\n * Element mechanics the host leaves unset keep defaults that throw a\n * setup-pointing error; the optional seams (`jsxDEV`, `transition`) are\n * routed around at the call sites 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/**\n * Mark synchronous work as non-urgent. `work` runs inline through the host\n * scheduler; queued subscriber updates inherit the designation and replay it\n * after dispatch. Without a host scheduler, normal timing is retained.\n */\nexport function transition(work: () => void): void {\n schedule(work, HOST.transition);\n}\n"],"mappings":";;;;;;;;AAmDA,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;;;;;;;;AASJ,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;;;;;;;AAQ3B,SAAgB,WAAW,MAAwB;AACjD,UAAS,MAAM,KAAK,WAAW"}
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.js CHANGED
@@ -1,5 +1,5 @@
1
- import { capture, event, listener, observer, pending, touch, watch } from "./observable.js";
2
- import { Context } from "./context.js";
1
+ import { capture, event, listener, observer, queued, touch, watch } from "./observable.js";
2
+ import { Context, join } from "./context.js";
3
3
 
4
4
  //#region src/state.ts
5
5
  const define = Object.defineProperty;
@@ -62,7 +62,7 @@ var State = class State {
62
62
  if (arg1 && typeof arg1 == "object") assign(self, arg1, arg2 === true);
63
63
  else if (arg2) apply(self, arg1, arg2);
64
64
  else event(self, arg1);
65
- return pending(self);
65
+ return queued(self);
66
66
  }
67
67
  /**
68
68
  * Iterate over managed properties in this instance of State.
@@ -145,7 +145,7 @@ function init(state, ...args) {
145
145
  return Context.root.add(state);
146
146
  }
147
147
  listener(state, (key) => {
148
- const rest = queued(state);
148
+ const rest = trailing(state);
149
149
  PENDING.delete(state);
150
150
  if (key === null) return null;
151
151
  parent(state, null);
@@ -370,14 +370,14 @@ function child(state) {
370
370
  reset();
371
371
  if (!(value instanceof State)) return;
372
372
  if (parent(value, state)) {
373
- const remove = ctx.add(value);
373
+ const remove = join(state, value);
374
374
  cleanup = () => {
375
375
  cancel();
376
376
  remove();
377
377
  event(value, null);
378
378
  };
379
379
  const cancel = listener(state, cleanup, null);
380
- } else if (!provides(ctx, value)) cleanup = ctx.add(value);
380
+ } else if (!provides(ctx, value)) cleanup = join(state, value);
381
381
  event(value);
382
382
  CHILDREN.get(state)?.forEach((cb) => cb(value));
383
383
  };
@@ -386,7 +386,7 @@ function child(state) {
386
386
  * Pending States constructed after this one - in a parent, the products of
387
387
  * its own initializers, until the last one it kept.
388
388
  */
389
- function queued(state) {
389
+ function trailing(state) {
390
390
  const rest = [];
391
391
  let seen = false;
392
392
  for (const item of PENDING) if (!seen) seen = item === state;
package/dist/state.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","names":[],"sources":["../src/state.ts"],"sourcesContent":["import { Context } from './context';\nimport {\n capture,\n event,\n listener,\n Observer,\n observer,\n pending,\n touch,\n watch\n} from './observable';\n\nconst define = Object.defineProperty;\n\n/** Register for all active states via string identifiers (usually unique). */\nconst ID = new WeakMap<State, string>();\n\n/** Internal state assigned to states. */\nconst STORE = new WeakMap<State, Record<string | number | symbol, unknown>>();\n\n/** States under construction - added on `new`, removed when activated or released.\n * Also carries work to run at the deadline, which `def` uses to bound its registry. */\nconst PENDING = new Set<State | (() => void)>();\n\n/** External lifecycle listeners for any given State class. */\nconst SETUP = new WeakMap<State.Extends, Set<State.Init<any> | State.On<any>>>();\n\n/** Parent-child relationships. */\nconst PARENT = new WeakMap<object, State | null>();\n\n/** Reference bound instance methods, or their getter, to real one. */\nconst UNBIND = new WeakMap<any, any>();\n\n/** List of methods defined by a given type. */\nconst METHODS = new WeakMap<Function, Map<string, (value: any) => void>>();\n\n/** List of reactive getters defined by a given type. */\nconst GETTERS = new WeakMap<Function, Map<string, () => unknown>>();\n\n/** Stale flags for compute closures awaiting refresh on next access. */\nconst STALE = new WeakSet<() => void>();\n\n/** Whether the deadline which drains `PENDING` is already queued for this tick. */\nlet QUEUED = false;\n\n/** Adopters for managed properties which have held a child State. */\nconst ADOPT = new WeakMap<State, Map<unknown, (value: unknown) => void>>();\nconst CHILDREN = new WeakMap<State, Set<(child: State) => void>>();\n\ndeclare namespace State {\n /** Any type of State, using own class constructor as its identifier. */\n type Extends<T extends State = State> = (abstract new (...args: any[]) => T) &\n typeof State;\n\n /** A State constructor which may be instanciated. */\n type Type<T extends State = State> = (new (...args: State.Args<T>) => T) &\n Omit<typeof State, never>;\n\n /** State constructor arguments */\n type Args<T extends State = any> = (Args<T> | Init<T> | Assign<T> | void)[];\n\n /**\n * Value of `static global`. A boolean opts a State in or out of the\n * process-global root; a resolver decides at activation, receiving the\n * instance and returning whether it registers - use it to make the choice\n * conditional (e.g. per environment). A bare literal (`= true` / `= false`)\n * seals the choice for subclasses; widen a subclass's `static global` type to\n * `State.Global` to permit a resolver or a later override.\n */\n type Global<T extends State = any> = boolean | ((self: T) => boolean);\n\n /**\n * State constructor callback - runs during activation, in argument order,\n * before the `new()` lifecycle hook (so it may configure state `new()`\n * will observe). Returned function will run when state is destroyed.\n */\n type Init<T extends State = State> = (\n this: T,\n thisArg: T\n ) => Promise<void> | (() => void) | Args<T> | Assign<T> | void;\n\n /**\n * Lifecycle handlers for `State.on`, keyed by when they run. A bare `Init`\n * function passed to `on` is sugar for `{ before }`.\n */\n interface On<T extends State = State> {\n /**\n * Per-class setup, run once when the class is first bootstrapped - before\n * its members are classified and bound. Receives the class, so a handler\n * may inspect or reshape the prototype first. A handler registered on a\n * base class runs for each subclass too.\n */\n type?(type: State.Extends<T>): void;\n\n /**\n * Per-instance setup, run in the `prepare` phase before `observe` and the\n * `new()` hook. Equivalent to passing a bare function to `on`. May return a\n * cleanup, constructor args, or an assign overlay.\n */\n before?(this: T, thisArg: T): void | (() => void) | Promise<void> | Args<T> | Assign<T>;\n\n /**\n * Per-instance setup, run at the `new()` slot - after own values are\n * observed and constructor args applied. May return a cleanup function.\n */\n after?(this: T, self: T): void | (() => void);\n }\n\n /** Object overlay to override values and methods on a state. */\n type Assign<T> = Record<string, unknown> & {\n [K in Field<T>]?: T[K] extends (...args: infer A) => infer R\n ? (this: T, ...args: A) => R\n : T[K];\n };\n\n /** Subset of `keyof T` not defined by base State. **/\n type Field<T> = Exclude<keyof T, keyof State>;\n\n /** Any valid key for state, including but not limited to Field<T>. */\n type Event<T = State> = Field<T> | number | symbol | (string & {});\n\n /** Any event signal dispatched to listeners, including lifecycle meta events. */\n type Signal<T = State> = Event<T> | true | false | null;\n\n /** Export/Import compatible value for a given property in a State. */\n type Export<R> = R extends State\n ? Values<R>\n : R extends { get(): infer T }\n ? T\n : R;\n\n /**\n * Values from current state of given state.\n * Differs from `Values` as values here will drill\n * into \"real\" values held by exotics like ref.Object.\n */\n type Values<T> = { [P in Field<T>]: Export<T[P]> };\n\n /** Object comperable to data found in T. */\n type Partial<T> = { [P in Field<T>]?: Export<T[P]> };\n\n /** Value for a property applied by a state. */\n type Value<T extends State, K extends State.Event<T>> = K extends keyof T\n ? Export<T[K]>\n : unknown;\n\n type Setter<T> = (value: T, previous: T) => T | void;\n\n /** Descriptor config for a managed property. */\n type Apply<T = any> = {\n value?: T;\n get?: ((source: State) => T) | boolean;\n set?: Setter<T> | boolean;\n enumerable?: boolean;\n // destroy?: () => void;\n };\n\n /** Descriptor config for set() overload - enforces type when key is a known field. */\n type Define<T, K> = K extends Field<T> ? Apply<T[K] | Export<T[K]>> : Apply;\n\n type OnEvent<T extends State> = (\n this: T,\n key: Signal<T>,\n source: T\n ) => void | (() => void) | null;\n\n /** Exotic value, where actual value is contained within. */\n type Ref<T = any> = {\n (next: T): void;\n current: T | null;\n };\n\n /**\n * A callback function which is subscribed to parent and updates when accessed properties change.\n *\n * @param current - Current state of this state. This is a proxy which detects properties which\n * where accessed, and thus depended upon to stay current.\n *\n * @param update - Set of properties which have changed, and events fired, since last update.\n *\n * @returns A callback function which will be called when this effect is stale.\n */\n type Effect<T> = (\n this: T,\n current: T,\n update: readonly State.Event<T>[] | undefined\n ) => EffectCallback | Promise<void> | null | void;\n\n /**\n * A callback function returned by effect. Will be called when effect is stale.\n *\n * @param update - `true` if update is pending, `false` effect has been cancelled, `null` if state is destroyed.\n */\n type EffectCallback = (update: boolean | null) => void;\n\n /**\n * A list of keys updated, or events fired, since last update.\n * This may be awaited to get full list (same array) when update is settled.\n */\n type Updated<T extends State> = readonly Event<T>[] &\n PromiseLike<readonly Event<T>[]>;\n}\n\nabstract class State {\n /**\n * Whether an instance activated with no enclosing context registers itself\n * to the process-global root, where `get()` can resolve it from anywhere.\n * `false` (the default) keeps a context-less instance fully functional but\n * private - not injectable, though it can still read declared globals. Opt in\n * with `static readonly global = true`; a resolver (see {@link State.Global})\n * makes the choice conditional. It must be declared per class - a subclass\n * that would inherit a global without its own declaration throws on\n * activation, so an accidental global (a forgotten `Provider`, an extended\n * global) cannot leak into the shared root.\n */\n static readonly global: State.Global = false;\n\n /**\n * Loopback to instance of this state. This is useful when in a subscribed context,\n * to keep write access to `this` after a destructure. You can use it to read variables silently as well.\n **/\n declare is: this;\n\n constructor(...args: State.Args) {\n define(this, 'is', { value: this });\n init(this, args, this.new);\n }\n\n /**\n * Optional lifecycle hook called during State initialization.\n * Can return a cleanup function to run when state is destroyed.\n *\n * It is recommended you protect this method.\n */\n protected new?(): void | (() => void);\n\n /**\n * Pull current values from state. Flattens all states and exotic values recursively.\n *\n * @returns Object with all values from this state.\n **/\n get(): State.Values<this>;\n\n /**\n * Run a function to run automatically when accessed values change.\n *\n * @param effect Function to run, and whenever accessed values change.\n * If effect returns a function, it will be called when a change occurs (syncronously),\n * effect is cancelled, or parent state is destroyed.\n * @returns Function to cancel listener.\n */\n get(effect: State.Effect<this>): () => void;\n\n /**\n * Get value of a property. Will fetch underlying value from exotic values like ref.Object.\n *\n * Any value which implements `get()` (with no arguments) will be treated as such.\n *\n * @param key - Property to get value of.\n * @param required - If true, will throw an error if property is not available.\n * @returns Value of property.\n */\n get<T extends State.Event<this>>(\n key: T,\n required?: boolean\n ): State.Value<this, T>;\n\n /**\n * Check if state is destroyed.\n *\n * @param status - `null` to check if state is destroyed.\n * @returns `true` if state is destroyed, `false` otherwise.\n */\n get(status: null): boolean;\n\n /**\n * Callback when state is to be destroyed.\n *\n * @param callback - Function to call when state is destroyed.\n * @returns Function to cancel listener.\n */\n get(status: null, callback: () => void): () => void;\n\n /** Fetch State of type from context. Throws if not found. */\n get<T extends State>(type: State.Type<T>, required?: true): T;\n\n /** Fetch a State from context. Undefined if not found. */\n get<T extends State>(type: State.Type<T>, required: boolean): T | undefined;\n\n /**\n * Subscribe to State becoming available in context.\n *\n * Will search both up and downstream by default.\n * Normally you can ignore this because State you expect is rarely both.\n *\n * Specify downstream if you only want to watch for State in children, which can be useful if you expect multiple of the same State in different branches of the tree.\n *\n * @param type - Type of State to watch for.\n * @param callback - Function to call when State is found. Will be called immediately if State is already available.\n * @param downstream - If true, will only watch for State in children, if false will only for parents.\n * @returns Function to cancel listener.\n */\n get<T extends State>(\n type: State.Type<T>,\n callback: Context.Expect<T>,\n downstream?: boolean\n ): () => void;\n\n get(\n arg1?: State.Effect<this> | State.Type | string | null,\n arg2?: boolean | Context.Expect | (() => void),\n arg3?: boolean\n ) {\n const self = this.is;\n\n if (arg1 === undefined) return values(self);\n if (State.is(arg1)) return Context.get(self).get(arg1, arg2, arg3, self);\n if (typeof arg1 == 'function') return watch(self, unbind(arg1));\n if (typeof arg2 == 'function') return callback(self, arg2, arg1);\n if (arg1 === null) return observer(self) === null;\n return access(self, arg1, arg2);\n }\n\n /**\n * Get update in progress.\n *\n * @returns Promise which resolves object with updated values, `undefined` if there no update is pending.\n **/\n set(): State.Updated<this>;\n\n /**\n * Merge argument with current state, updating one or more properties at once.\n * Properties which are not managed by this state will be ignored.\n *\n * @param assign - Object with properties to update.\n * @param silent - If true, listeners will not be notified. If state is destroyed, will squash update without throwing.\n * @returns Array of keys updated, syncronously contains keys updated immediately and may be resolved (to itself) when all updates are settled.\n */\n set(assign?: State.Assign<this>, silent?: boolean): State.Updated<this>;\n\n /**\n * Call a function when update occurs.\n *\n * Given function is called for every assignment (which changes value) or explicit `set`.\n *\n * To run logic on final value only, callback may return a function. The same\n * function for one or more events will be called only once when update is settled.\n *\n * Return `null` from callback to stop listening.\n *\n * @param callback - Function to call when update occurs.\n * @returns Function to remove listener. Will return `true` if removed, `false` if inactive already.\n */\n set(callback: State.OnEvent<this>): () => boolean;\n\n /**\n * Push an update. This will not change the value of associated property.\n *\n * Useful where a property value internally has changed, but the object is the same.\n * For example: An array has pushed a new value, or a nested property is updated.\n *\n * You can also use this to dispatch arbitrary events.\n * Symbols are recommended as non-property events, however you can use any string.\n * If doing so, be sure to avoid collisions using property names. An easy way to do this is\n * to prefix an event with \"!\" and/or use dash-case. e.g. `set(\"!event\")` or `set(\"my-event\")`.\n *\n * @param key - Property or event to dispatch.\n * @returns Promise resolves an array of keys updated.\n */\n set(key: State.Event<this>): State.Updated<this>;\n\n /**\n * Declare an end to updates. This event is final and will freeze state.\n * This event can be watched for as well, to run cleanup logic and internally will remove all listeners.\n *\n * @param status - `null` to end updates.\n */\n set(status: null): void;\n\n /**\n * Register a callback for a specific property or event.\n *\n * Callback receives the key, current value, and source instance.\n *\n * @param event - Property or event to watch. If `null`, will callback on destroy.\n * @param callback - Function to call when event occurs.\n * @returns Function to remove listener.\n */\n set<K extends State.Event<this>>(\n event: K | null,\n callback: State.OnEvent<this>\n ): () => boolean;\n\n /**\n * Define or update a managed property using a descriptor config.\n * If the property already is managed, config will only accept value.\n * If the property does not exist, it will be created and made reactive.\n *\n * @param key - Property to define or update.\n * @param config - Descriptor config with value, get, set, enumerable, and/or destroy.\n * @returns Promise resolves an array of keys updated.\n */\n set<K extends State.Event<this>>(\n key: K,\n config: State.Define<this, K>\n ): State.Updated<this>;\n\n set(\n arg1?: State.OnEvent<this> | State.Assign<this> | State.Event<this> | null,\n arg2?: unknown\n ) {\n const self = this.is;\n\n if (typeof arg1 == 'function')\n return listener(self, (key) => {\n if (\n typeof key == 'string' ||\n typeof key == 'number' ||\n typeof key == 'symbol'\n )\n return arg1.call(self, key, self);\n });\n\n if (typeof arg2 == 'function')\n return callback(self, arg2, arg1 as State.Signal);\n\n if (arg1 && typeof arg1 == 'object') assign(self, arg1, arg2 === true);\n else if (arg2) apply(self, arg1 as string, arg2);\n else event(self, arg1);\n\n return pending(self) as State.Updated<this>;\n }\n\n /**\n * Iterate over managed properties in this instance of State.\n * Yeilds the key and current value for each property.\n */\n [Symbol.iterator](): Iterator<[string, unknown]> {\n return Object.entries(STORE.get(this.is)!)[Symbol.iterator]();\n }\n\n /**\n * Create and activate a new instance of this state.\n *\n * **Important** - Unlike `new this(...)` - this method also activates state.\n *\n * @param args - arguments sent to constructor\n */\n static new<T extends State>(this: State.Type<T>, ...args: State.Args<T>): T {\n const instance = new this(...args);\n event(instance);\n return instance;\n }\n\n /**\n * Static equivalent of `x instanceof this`.\n * Determines if provided class is a subtype of this one.\n * If so, language server will make available all static\n * methods and properties of this class.\n */\n static is<T extends State.Extends>(this: T, maybe: unknown): maybe is T {\n return (\n maybe === this ||\n (typeof maybe == 'function' && maybe.prototype instanceof this)\n );\n }\n\n /**\n * Register a lifecycle handler for this State and its subclasses.\n *\n * A bare function is per-instance setup run in the `prepare` phase (sugar for\n * `{ before }`); if it returns a function, that runs when the instance is\n * destroyed. Pass a {@link State.On} object to hook by cadence - `type`\n * (per-class, at bootstrap), `before` (per-instance, before `new()`), and\n * `after` (per-instance, at the `new()` slot).\n *\n * @returns Function to remove the handler.\n */\n static on<T extends State>(\n this: State.Extends<T>,\n handler: State.Init<T> | State.On<T>\n ) {\n let setup = SETUP.get(this);\n\n if (!setup) SETUP.set(this, (setup = new Set()));\n\n setup.add(handler);\n\n return () => setup.delete(handler);\n }\n}\n\ndefine(State.prototype, 'toString', {\n value() {\n return ID.get(this.is);\n }\n});\n\ndefine(State, 'toString', {\n value() {\n return this.name;\n }\n});\n\n/** Register a user OnEvent callback, preserving `this` and `source`. */\nfunction callback<T extends State>(\n self: T,\n cb: Function,\n select?: Observer.Signal | Set<Observer.Signal>\n) {\n return listener(self, (key) => cb.call(self, key, self), select);\n}\n\n/**\n * Apply state arguemnts, run callbacks and observe properties.\n * Accumulate and handle cleanup events.\n **/\nfunction init(state: State, ...args: State.Args) {\n const T = state.constructor as State.Extends;\n\n if (T === State) throw new Error('Cannot create base State.');\n\n const { before, after } = bootstrap(T);\n\n ID.set(state, `${T}-${uid()}`);\n STORE.set(state, {});\n\n function observe() {\n for (const key in state) {\n const desc: PropertyDescriptor = Object.getOwnPropertyDescriptor(state, key) || {};\n\n if ('value' in desc && desc.configurable) apply(state, key, desc, true);\n }\n }\n\n function register() {\n if (Context.get(state) !== Context.root) return;\n\n const type = state.constructor as typeof State;\n const g = type.global;\n\n if (!(typeof g == 'function' ? g(state) : g)) return;\n\n if (!Object.prototype.hasOwnProperty.call(type, 'global'))\n throw new Error(\n `${state} would register as a global by inheritance alone - re-declare \\`static global\\` on ${type.name} (\\`true\\` to keep it, \\`false\\` to opt out).`\n );\n\n return Context.root.add(state);\n }\n\n listener(state, (key) => {\n const rest = queued(state);\n\n PENDING.delete(state);\n\n if (key === null) return null;\n\n parent(state, null);\n\n const queue = [...before, observe, ...args, ...after, register];\n\n capture((release) => {\n listener(state, () => release(null), null);\n\n for (let i = 0; i < queue.length; i++) {\n const arg = queue[i];\n const out = typeof arg == 'function' ? arg.call(state, state) : arg;\n\n if (out instanceof Promise)\n out.catch((err) => {\n console.error(`Async error in constructor for ${state}:`);\n console.error(err);\n });\n else if (Array.isArray(out)) queue.splice(i + 1, 0, ...out);\n else if (typeof out == 'function') listener(state, out, null);\n else if (typeof out == 'object') assign(state, out, true);\n }\n });\n\n let end = rest.length;\n\n while (end-- > 0 && PENDING.has(rest[end]));\n\n for (let i = 0; i < end; i++) PENDING.delete(rest[i]);\n\n return null;\n });\n\n if (!QUEUED) {\n QUEUED = true;\n\n queueMicrotask(() => {\n QUEUED = false;\n\n for (const item of PENDING)\n if (typeof item == 'function') item();\n else console.warn(`${item} was constructed but never activated.`);\n\n PENDING.clear();\n });\n }\n\n PENDING.add(state);\n}\n\n/**\n * Apply instructions and inherited event listeners. Ensure class metadata is ready.\n *\n * @param T - State class to bootstrap.\n * @return Array of init functions to run on instance, in order of class hierarchy.\n */\nfunction bootstrap(T: State.Extends) {\n const chain = [] as State.Extends[];\n const before = new Set<State.Init>();\n const after = new Set<State.Init>();\n const onType = new Set<NonNullable<State.On['type']>>();\n let keys = new Map<string, (value: any) => void>();\n let getters = new Map<string, () => unknown>();\n\n while (true) {\n chain.unshift(T);\n if (T === State) break;\n T = Object.getPrototypeOf(T);\n }\n\n for (const type of chain) {\n for (const handler of SETUP.get(type) || [])\n if (typeof handler == 'function') before.add(handler);\n else {\n if (handler.before) before.add(handler.before);\n if (handler.after) after.add(handler.after);\n if (handler.type) onType.add(handler.type);\n }\n\n if (type === State) continue;\n\n if (METHODS.has(type)) {\n keys = METHODS.get(type)!;\n getters = GETTERS.get(type)!;\n continue;\n }\n\n for (const setupType of onType) setupType(type);\n\n METHODS.set(type, (keys = new Map(keys)));\n GETTERS.set(type, (getters = new Map(getters)));\n\n for (const [key, desc] of Object.entries(\n Object.getOwnPropertyDescriptors(type.prototype)\n )) {\n if (key == 'constructor' || !desc.configurable) continue;\n\n if (typeof desc.get == 'function') {\n if (desc.configurable && typeof desc.set != 'function')\n getters.set(key, desc.get);\n\n continue;\n }\n\n const { value } = desc;\n\n if (typeof value !== 'function') continue;\n\n function bind(this: State, original?: Function) {\n const { is } = this;\n\n if (is.hasOwnProperty(key) && !original) return value as Function;\n\n const fn = original || value;\n const bound = fn.bind(is);\n\n UNBIND.set(bound, fn);\n define(is, key, { value: bound, writable: true, configurable: true });\n\n return bound;\n }\n\n UNBIND.set(bind, value);\n\n keys.set(key, bind);\n define(type.prototype, key, { get: bind, set: bind });\n }\n }\n\n if (getters.size)\n before.add((self) => getters.forEach(compute, self));\n\n return { before, after };\n}\n\n/**\n * Install a reactive computed property on a state instance, derived from a prototype\n * getter or an arity-bearing `set` factory.\n *\n * The getter is invoked with the tracking proxy as both `this` and its first argument;\n * reads of managed properties through it create subscriptions. Result is cached and\n * emits a keyed event when stale.\n */\nfunction compute(this: State, getter: (self: any) => unknown, key: string) {\n const store = STORE.get(this)!;\n let reset: (() => void) | undefined;\n let isAsync: boolean;\n let proxy: any;\n\n const connect = () => {\n reset = watch(\n this,\n (current) => {\n proxy = current;\n\n if (!(key in store) || STALE.delete(run)) run(!reset);\n\n return (didUpdate) => {\n if (didUpdate) {\n STALE.add(run);\n event(this, key, true);\n }\n };\n },\n false\n );\n };\n\n const run = (initial?: boolean) => {\n let next: unknown;\n\n try {\n next = getter.call(proxy, proxy);\n } catch (err) {\n console.warn(\n `An exception was thrown while ${initial ? 'initializing' : 'refreshing'\n } ${this}.${key}.`\n );\n\n if (initial) throw err;\n\n console.error(err);\n }\n\n update(this, key, next, !isAsync);\n };\n\n apply(\n this,\n key,\n {\n enumerable: true,\n set: false,\n get: () => {\n if (!proxy) {\n if (observer(this) === null) return store[key];\n\n connect();\n isAsync = true;\n }\n\n if (STALE.delete(run)) run();\n\n return access(this, key, !proxy);\n }\n },\n true\n );\n}\n\n/**\n * Define or update a managed property using a descriptor config.\n * If the property already is managed, config will only accept value.\n * If the property does not exist, it will be created and made reactive.\n *\n * @param state - State to apply property to.\n * @param key - Property to define or update.\n * @param config - Descriptor config with value, get, set, enumerable, and/or destroy.\n * @param silent - If an update does occur, listeners will not be refreshed automatically.\n */\nfunction apply(\n state: State,\n key: string,\n config: State.Apply,\n silent?: boolean\n) {\n const desc = Object.getOwnPropertyDescriptor(state, key);\n\n if (desc && 'get' in desc) {\n if (Object.keys(config).some((k) => k != 'value'))\n throw new Error(`Property ${key} on ${state} is already defined.`);\n if ('value' in config) update(state, key, config.value, silent);\n return;\n }\n\n function set(value: unknown, silent?: boolean) {\n update(state, key, value, silent, true);\n }\n\n define(state, key, {\n configurable: true,\n enumerable: config.enumerable !== false,\n get(this: State) {\n const value =\n typeof config.get == 'function'\n ? config.get(this)\n : access(state, key, config.get);\n\n return touch(this, key, value);\n },\n set(next: any, silent?: boolean) {\n if (config.set === false)\n throw new Error(`${state}.${String(key)} is read-only.`);\n\n if (typeof config.set == 'function')\n try {\n const output = config.set(next, STORE.get(state)![key]);\n if (output !== undefined) next = output;\n } catch (err: unknown) {\n if (err === false) return;\n if (err === true) {\n set(next, true);\n return;\n }\n throw err;\n }\n\n set(next, silent);\n }\n });\n\n if ('value' in config) set(config.value, silent);\n}\n\nfunction provides(ctx: Context, value: State) {\n while (ctx = ctx.parent!) {\n const entries = ctx.provide.get(value.constructor as State.Extends);\n if (entries) for (const [state] of entries) if (state === value) return true;\n }\n}\n\nfunction child(state: State) {\n let cleanup: (() => void) | undefined;\n const ctx = Context.get(state);\n\n function reset() {\n if (cleanup) cleanup();\n cleanup = undefined;\n }\n\n listener(state, reset, null);\n\n return (value: unknown) => {\n reset();\n\n if (!(value instanceof State)) return;\n\n if (parent(value, state)) {\n const remove = ctx.add(value);\n cleanup = () => {\n cancel();\n remove();\n event(value, null);\n };\n const cancel = listener(state, cleanup, null);\n } else if (!provides(ctx, value)) {\n cleanup = ctx.add(value);\n }\n\n event(value);\n\n CHILDREN.get(state)?.forEach((cb) => cb(value));\n };\n}\n\n/**\n * Pending States constructed after this one - in a parent, the products of\n * its own initializers, until the last one it kept.\n */\nfunction queued(state: State) {\n const rest: State[] = [];\n let seen = false;\n\n for (const item of PENDING)\n if (!seen) seen = item === state;\n else if (item instanceof State) rest.push(item);\n\n return rest;\n}\n\n/**\n * Report States adopted by a parent - those already held, then each one\n * claimed later. Returns a callback to stop watching.\n */\nfunction children(state: State, callback: (child: State) => void) {\n const store = STORE.get(state)!;\n const keys = ADOPT.get(state);\n\n if (keys)\n for (const key of keys.keys()) {\n const value = store[key as string];\n if (value instanceof State) callback(value);\n }\n\n let set = CHILDREN.get(state);\n\n if (!set) CHILDREN.set(state, (set = new Set()));\n\n set.add(callback);\n\n return () => set!.delete(callback);\n}\n\n/** Currently accumulating export. Stores real values of placeholder properties such as ref() or child states. */\nlet EXPORT: Map<any, any> | undefined;\n\nfunction values<T extends State>(state: T): State.Values<T> {\n const values = {} as any;\n let notRecursive;\n\n if (!EXPORT) {\n notRecursive = true;\n EXPORT = new Map();\n }\n\n EXPORT.set(state, values);\n\n for (let [key, value] of state) {\n if (EXPORT.has(value)) value = EXPORT.get(value);\n else if (\n value &&\n typeof value == 'object' &&\n 'get' in value &&\n typeof value.get === 'function'\n )\n value = value.get();\n\n values[key] = value;\n }\n\n if (notRecursive) EXPORT = undefined;\n\n return Object.freeze(values);\n}\n\nfunction access(state: State, property: string, required?: boolean) {\n const store = STORE.get(state)!;\n\n if (property in store || required === false) {\n const value = store[property];\n\n if (value !== undefined || !required) return value;\n }\n\n if (METHODS.get(state.constructor)!.has(property))\n return unbind((state as any)[property]);\n\n if (observer(state) === null) return undefined;\n\n const error = new Error(`${state}.${property} is not yet available.`);\n const promise = new Promise<any>((resolve, reject) => {\n listener(state, (key) => {\n if (key === property) {\n resolve(store[key]);\n return null;\n }\n\n if (key === null) {\n reject(new Error(`${state} is destroyed.`));\n }\n });\n });\n\n throw Object.assign(promise, {\n toString: () => String(error),\n name: 'Suspense',\n message: error.message,\n stack: error.stack\n });\n}\n\nfunction assign(state: State, data: State.Assign<State>, silent?: boolean) {\n if (!silent) event(state);\n\n const methods = METHODS.get(state.constructor)!;\n const getters = GETTERS.get(state.constructor);\n\n for (const key in data) {\n const bind = methods.get(key);\n\n if (bind) bind.call(state, data[key]);\n else if (getters?.has(key)) continue;\n else if (key in state && key !== 'is') {\n const desc: PropertyDescriptor = Object.getOwnPropertyDescriptor(state, key) || {};\n const set = desc.set as (value: any, silent?: boolean) => void;\n\n if (set) {\n set.call(state, data[key], silent);\n } else {\n (state as any)[key] = data[key];\n }\n }\n }\n}\n\n/**\n * Update a property on a state instance and notify listeners.\n *\n * 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.\n *\n * If `silent` is true, the update will not dispatch events and will return `false` instead of throwing if state is destroyed.\n */\nfunction update<T>(\n state: State,\n key: State.Event<T>,\n value: T,\n silent?: boolean,\n own?: boolean\n) {\n if (observer(state) === null) {\n if (silent) return false;\n throw new Error(\n `Tried to update ${state}.${String(key)} but state is destroyed.`\n );\n }\n\n const store = STORE.get(state)!;\n\n if (value instanceof State) value = value.is as T;\n\n if (key in store && value === store[key]) return false;\n\n store[key] = value;\n\n if (!silent) event(state, key);\n\n if (own) adopt(state, key, value);\n\n return true;\n}\n\n/**\n * Hand a value stored by an owning writer to that property's adopter,\n * creating one the first time a State is stored there. A property which has\n * held a State keeps its adopter, so a later non-State value releases the\n * previous child.\n */\nfunction adopt(state: State, key: unknown, value: unknown) {\n let keys = ADOPT.get(state);\n\n if (!keys) {\n if (!(value instanceof State)) return;\n ADOPT.set(state, (keys = new Map()));\n }\n\n let claim = keys.get(key);\n\n if (!claim) {\n if (!(value instanceof State)) return;\n keys.set(key, (claim = child(state)));\n }\n\n claim(value);\n}\n\n/** Random alphanumberic of length 6; always starts with a letter. */\nfunction uid() {\n return (0.278 + Math.random() * 0.722)\n .toString(36)\n .substring(2, 8)\n .toUpperCase();\n}\n\nfunction unbind<T extends Function>(fn: T): T;\nfunction unbind<T extends Function>(fn?: T): T | undefined;\nfunction unbind(fn?: Function) {\n return UNBIND.get(fn) || fn;\n}\n\n/**\n * Read or claim a parent for a given child. In read mode (one argument) returns\n * the current parent, or `undefined` if never assigned. In write mode assigns\n * only if unclaimed and returns whether the assignment applied - `true` means\n * this call freshly claimed it, `false` means it was already parented.\n */\nfunction parent(child: object): State | null | undefined;\nfunction parent(child: object, value: State | null): boolean;\nfunction parent(child: object, value?: State | null) {\n if (arguments.length < 2) return PARENT.get(child as State);\n if (PARENT.has(child as State)) return false;\n PARENT.set(child as State, value ?? null);\n return true;\n}\n\nexport { event, unbind, State, parent, children, PENDING, STORE, uid, access, update, apply, compute };\n"],"mappings":"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"}
1
+ {"version":3,"file":"state.js","names":[],"sources":["../src/state.ts"],"sourcesContent":["import { Context, join } from './context';\nimport {\n capture,\n event,\n listener,\n Observer,\n observer,\n queued,\n touch,\n watch\n} from './observable';\n\nconst define = Object.defineProperty;\n\n/** Register for all active states via string identifiers (usually unique). */\nconst ID = new WeakMap<State, string>();\n\n/** Internal state assigned to states. */\nconst STORE = new WeakMap<State, Record<string | number | symbol, unknown>>();\n\n/** States under construction - added on `new`, removed when activated or released.\n * Also carries work to run at the deadline, which `def` uses to bound its registry. */\nconst PENDING = new Set<State | (() => void)>();\n\n/** External lifecycle listeners for any given State class. */\nconst SETUP = new WeakMap<State.Extends, Set<State.Init<any> | State.On<any>>>();\n\n/** Parent-child relationships. */\nconst PARENT = new WeakMap<object, State | null>();\n\n/** Reference bound instance methods, or their getter, to real one. */\nconst UNBIND = new WeakMap<any, any>();\n\n/** List of methods defined by a given type. */\nconst METHODS = new WeakMap<Function, Map<string, (value: any) => void>>();\n\n/** List of reactive getters defined by a given type. */\nconst GETTERS = new WeakMap<Function, Map<string, () => unknown>>();\n\n/** Stale flags for compute closures awaiting refresh on next access. */\nconst STALE = new WeakSet<() => void>();\n\n/** Whether the deadline which drains `PENDING` is already queued for this tick. */\nlet QUEUED = false;\n\n/** Adopters for managed properties which have held a child State. */\nconst ADOPT = new WeakMap<State, Map<unknown, (value: unknown) => void>>();\nconst CHILDREN = new WeakMap<State, Set<(child: State) => void>>();\n\ndeclare namespace State {\n /** Any type of State, using own class constructor as its identifier. */\n type Extends<T extends State = State> = (abstract new (...args: any[]) => T) &\n typeof State;\n\n /** A State constructor which may be instanciated. */\n type Type<T extends State = State> = (new (...args: State.Args<T>) => T) &\n Omit<typeof State, never>;\n\n /** State constructor arguments */\n type Args<T extends State = any> = (Args<T> | Init<T> | Assign<T> | void)[];\n\n /**\n * Value of `static global`. A boolean opts a State in or out of the\n * process-global root; a resolver decides at activation, receiving the\n * instance and returning whether it registers - use it to make the choice\n * conditional (e.g. per environment). A bare literal (`= true` / `= false`)\n * seals the choice for subclasses; widen a subclass's `static global` type to\n * `State.Global` to permit a resolver or a later override.\n */\n type Global<T extends State = any> = boolean | ((self: T) => boolean);\n\n /**\n * State constructor callback - runs during activation, in argument order,\n * before the `new()` lifecycle hook (so it may configure state `new()`\n * will observe). Returned function will run when state is destroyed.\n */\n type Init<T extends State = State> = (\n this: T,\n thisArg: T\n ) => Promise<void> | (() => void) | Args<T> | Assign<T> | void;\n\n /**\n * Lifecycle handlers for `State.on`, keyed by when they run. A bare `Init`\n * function passed to `on` is sugar for `{ before }`.\n */\n interface On<T extends State = State> {\n /**\n * Per-class setup, run once when the class is first bootstrapped - before\n * its members are classified and bound. Receives the class, so a handler\n * may inspect or reshape the prototype first. A handler registered on a\n * base class runs for each subclass too.\n */\n type?(type: State.Extends<T>): void;\n\n /**\n * Per-instance setup, run in the `prepare` phase before `observe` and the\n * `new()` hook. Equivalent to passing a bare function to `on`. May return a\n * cleanup, constructor args, or an assign overlay.\n */\n before?(this: T, thisArg: T): void | (() => void) | Promise<void> | Args<T> | Assign<T>;\n\n /**\n * Per-instance setup, run at the `new()` slot - after own values are\n * observed and constructor args applied. May return a cleanup function.\n */\n after?(this: T, self: T): void | (() => void);\n }\n\n /** Object overlay to override values and methods on a state. */\n type Assign<T> = Record<string, unknown> & {\n [K in Field<T>]?: T[K] extends (...args: infer A) => infer R\n ? (this: T, ...args: A) => R\n : T[K];\n };\n\n /** Subset of `keyof T` not defined by base State. **/\n type Field<T> = Exclude<keyof T, keyof State>;\n\n /** Any valid key for state, including but not limited to Field<T>. */\n type Event<T = State> = Field<T> | number | symbol | (string & {});\n\n /** Any event signal dispatched to listeners, including lifecycle meta events. */\n type Signal<T = State> = Event<T> | true | false | null;\n\n /** Export/Import compatible value for a given property in a State. */\n type Export<R> = R extends State\n ? Values<R>\n : R extends { get(): infer T }\n ? T\n : R;\n\n /**\n * Values from current state of given state.\n * Differs from `Values` as values here will drill\n * into \"real\" values held by exotics like ref.Object.\n */\n type Values<T> = { [P in Field<T>]: Export<T[P]> };\n\n /** Object comperable to data found in T. */\n type Partial<T> = { [P in Field<T>]?: Export<T[P]> };\n\n /** Value for a property applied by a state. */\n type Value<T extends State, K extends State.Event<T>> = K extends keyof T\n ? Export<T[K]>\n : unknown;\n\n type Setter<T> = (value: T, previous: T) => T | void;\n\n /** Descriptor config for a managed property. */\n type Apply<T = any> = {\n value?: T;\n get?: ((source: State) => T) | boolean;\n set?: Setter<T> | boolean;\n enumerable?: boolean;\n // destroy?: () => void;\n };\n\n /** Descriptor config for set() overload - enforces type when key is a known field. */\n type Define<T, K> = K extends Field<T> ? Apply<T[K] | Export<T[K]>> : Apply;\n\n type OnEvent<T extends State> = (\n this: T,\n key: Signal<T>,\n source: T\n ) => void | (() => void) | null;\n\n /** Exotic value, where actual value is contained within. */\n type Ref<T = any> = {\n (next: T): void;\n current: T | null;\n };\n\n /**\n * A callback function which is subscribed to parent and updates when accessed properties change.\n *\n * @param current - Current state of this state. This is a proxy which detects properties which\n * where accessed, and thus depended upon to stay current.\n *\n * @param update - Set of properties which have changed, and events fired, since last update.\n *\n * @returns A callback function which will be called when this effect is stale.\n */\n type Effect<T> = (\n this: T,\n current: T,\n update: readonly State.Event<T>[] | undefined\n ) => EffectCallback | Promise<void> | null | void;\n\n /**\n * A callback function returned by effect. Will be called when effect is stale.\n *\n * @param update - `true` if update is pending, `false` effect has been cancelled, `null` if state is destroyed.\n */\n type EffectCallback = (update: boolean | null) => void;\n\n /**\n * A list of keys updated, or events fired, since last update.\n * This may be awaited to get full list (same array) when update is settled.\n */\n type Updated<T extends State> = readonly Event<T>[] &\n PromiseLike<readonly Event<T>[]>;\n}\n\nabstract class State {\n /**\n * Whether an instance activated with no enclosing context registers itself\n * to the process-global root, where `get()` can resolve it from anywhere.\n * `false` (the default) keeps a context-less instance fully functional but\n * private - not injectable, though it can still read declared globals. Opt in\n * with `static readonly global = true`; a resolver (see {@link State.Global})\n * makes the choice conditional. It must be declared per class - a subclass\n * that would inherit a global without its own declaration throws on\n * activation, so an accidental global (a forgotten `Provider`, an extended\n * global) cannot leak into the shared root.\n */\n static readonly global: State.Global = false;\n\n /**\n * Loopback to instance of this state. This is useful when in a subscribed context,\n * to keep write access to `this` after a destructure. You can use it to read variables silently as well.\n **/\n declare is: this;\n\n constructor(...args: State.Args) {\n define(this, 'is', { value: this });\n init(this, args, this.new);\n }\n\n /**\n * Optional lifecycle hook called during State initialization.\n * Can return a cleanup function to run when state is destroyed.\n *\n * It is recommended you protect this method.\n */\n protected new?(): void | (() => void);\n\n /**\n * Pull current values from state. Flattens all states and exotic values recursively.\n *\n * @returns Object with all values from this state.\n **/\n get(): State.Values<this>;\n\n /**\n * Run a function to run automatically when accessed values change.\n *\n * @param effect Function to run, and whenever accessed values change.\n * If effect returns a function, it will be called when a change occurs (syncronously),\n * effect is cancelled, or parent state is destroyed.\n * @returns Function to cancel listener.\n */\n get(effect: State.Effect<this>): () => void;\n\n /**\n * Get value of a property. Will fetch underlying value from exotic values like ref.Object.\n *\n * Any value which implements `get()` (with no arguments) will be treated as such.\n *\n * @param key - Property to get value of.\n * @param required - If true, will throw an error if property is not available.\n * @returns Value of property.\n */\n get<T extends State.Event<this>>(\n key: T,\n required?: boolean\n ): State.Value<this, T>;\n\n /**\n * Check if state is destroyed.\n *\n * @param status - `null` to check if state is destroyed.\n * @returns `true` if state is destroyed, `false` otherwise.\n */\n get(status: null): boolean;\n\n /**\n * Callback when state is to be destroyed.\n *\n * @param callback - Function to call when state is destroyed.\n * @returns Function to cancel listener.\n */\n get(status: null, callback: () => void): () => void;\n\n /** Fetch State of type from context. Throws if not found. */\n get<T extends State>(type: State.Type<T>, required?: true): T;\n\n /** Fetch a State from context. Undefined if not found. */\n get<T extends State>(type: State.Type<T>, required: boolean): T | undefined;\n\n /**\n * Subscribe to State becoming available in context.\n *\n * Will search both up and downstream by default.\n * Normally you can ignore this because State you expect is rarely both.\n *\n * Specify downstream if you only want to watch for State in children, which can be useful if you expect multiple of the same State in different branches of the tree.\n *\n * @param type - Type of State to watch for.\n * @param callback - Function to call when State is found. Will be called immediately if State is already available.\n * @param downstream - If true, will only watch for State in children, if false will only for parents.\n * @returns Function to cancel listener.\n */\n get<T extends State>(\n type: State.Type<T>,\n callback: Context.Expect<T>,\n downstream?: boolean\n ): () => void;\n\n get(\n arg1?: State.Effect<this> | State.Type | string | null,\n arg2?: boolean | Context.Expect | (() => void),\n arg3?: boolean\n ) {\n const self = this.is;\n\n if (arg1 === undefined) return values(self);\n if (State.is(arg1)) return Context.get(self).get(arg1, arg2, arg3, self);\n if (typeof arg1 == 'function') return watch(self, unbind(arg1));\n if (typeof arg2 == 'function') return callback(self, arg2, arg1);\n if (arg1 === null) return observer(self) === null;\n return access(self, arg1, arg2);\n }\n\n /**\n * Get update in progress.\n *\n * @returns Promise which resolves object with updated values, `undefined` if there no update is pending.\n **/\n set(): State.Updated<this>;\n\n /**\n * Merge argument with current state, updating one or more properties at once.\n * Properties which are not managed by this state will be ignored.\n *\n * @param assign - Object with properties to update.\n * @param silent - If true, listeners will not be notified. If state is destroyed, will squash update without throwing.\n * @returns Array of keys updated, syncronously contains keys updated immediately and may be resolved (to itself) when all updates are settled.\n */\n set(assign?: State.Assign<this>, silent?: boolean): State.Updated<this>;\n\n /**\n * Call a function when update occurs.\n *\n * Given function is called for every assignment (which changes value) or explicit `set`.\n *\n * To run logic on final value only, callback may return a function. The same\n * function for one or more events will be called only once when update is settled.\n *\n * Return `null` from callback to stop listening.\n *\n * @param callback - Function to call when update occurs.\n * @returns Function to remove listener. Will return `true` if removed, `false` if inactive already.\n */\n set(callback: State.OnEvent<this>): () => boolean;\n\n /**\n * Push an update. This will not change the value of associated property.\n *\n * Useful where a property value internally has changed, but the object is the same.\n * For example: An array has pushed a new value, or a nested property is updated.\n *\n * You can also use this to dispatch arbitrary events.\n * Symbols are recommended as non-property events, however you can use any string.\n * If doing so, be sure to avoid collisions using property names. An easy way to do this is\n * to prefix an event with \"!\" and/or use dash-case. e.g. `set(\"!event\")` or `set(\"my-event\")`.\n *\n * @param key - Property or event to dispatch.\n * @returns Promise resolves an array of keys updated.\n */\n set(key: State.Event<this>): State.Updated<this>;\n\n /**\n * Declare an end to updates. This event is final and will freeze state.\n * This event can be watched for as well, to run cleanup logic and internally will remove all listeners.\n *\n * @param status - `null` to end updates.\n */\n set(status: null): void;\n\n /**\n * Register a callback for a specific property or event.\n *\n * Callback receives the key, current value, and source instance.\n *\n * @param event - Property or event to watch. If `null`, will callback on destroy.\n * @param callback - Function to call when event occurs.\n * @returns Function to remove listener.\n */\n set<K extends State.Event<this>>(\n event: K | null,\n callback: State.OnEvent<this>\n ): () => boolean;\n\n /**\n * Define or update a managed property using a descriptor config.\n * If the property already is managed, config will only accept value.\n * If the property does not exist, it will be created and made reactive.\n *\n * @param key - Property to define or update.\n * @param config - Descriptor config with value, get, set, enumerable, and/or destroy.\n * @returns Promise resolves an array of keys updated.\n */\n set<K extends State.Event<this>>(\n key: K,\n config: State.Define<this, K>\n ): State.Updated<this>;\n\n set(\n arg1?: State.OnEvent<this> | State.Assign<this> | State.Event<this> | null,\n arg2?: unknown\n ) {\n const self = this.is;\n\n if (typeof arg1 == 'function')\n return listener(self, (key) => {\n if (\n typeof key == 'string' ||\n typeof key == 'number' ||\n typeof key == 'symbol'\n )\n return arg1.call(self, key, self);\n });\n\n if (typeof arg2 == 'function')\n return callback(self, arg2, arg1 as State.Signal);\n\n if (arg1 && typeof arg1 == 'object') assign(self, arg1, arg2 === true);\n else if (arg2) apply(self, arg1 as string, arg2);\n else event(self, arg1);\n\n return queued(self) as State.Updated<this>;\n }\n\n /**\n * Iterate over managed properties in this instance of State.\n * Yeilds the key and current value for each property.\n */\n [Symbol.iterator](): Iterator<[string, unknown]> {\n return Object.entries(STORE.get(this.is)!)[Symbol.iterator]();\n }\n\n /**\n * Create and activate a new instance of this state.\n *\n * **Important** - Unlike `new this(...)` - this method also activates state.\n *\n * @param args - arguments sent to constructor\n */\n static new<T extends State>(this: State.Type<T>, ...args: State.Args<T>): T {\n const instance = new this(...args);\n event(instance);\n return instance;\n }\n\n /**\n * Static equivalent of `x instanceof this`.\n * Determines if provided class is a subtype of this one.\n * If so, language server will make available all static\n * methods and properties of this class.\n */\n static is<T extends State.Extends>(this: T, maybe: unknown): maybe is T {\n return (\n maybe === this ||\n (typeof maybe == 'function' && maybe.prototype instanceof this)\n );\n }\n\n /**\n * Register a lifecycle handler for this State and its subclasses.\n *\n * A bare function is per-instance setup run in the `prepare` phase (sugar for\n * `{ before }`); if it returns a function, that runs when the instance is\n * destroyed. Pass a {@link State.On} object to hook by cadence - `type`\n * (per-class, at bootstrap), `before` (per-instance, before `new()`), and\n * `after` (per-instance, at the `new()` slot).\n *\n * @returns Function to remove the handler.\n */\n static on<T extends State>(\n this: State.Extends<T>,\n handler: State.Init<T> | State.On<T>\n ) {\n let setup = SETUP.get(this);\n\n if (!setup) SETUP.set(this, (setup = new Set()));\n\n setup.add(handler);\n\n return () => setup.delete(handler);\n }\n}\n\ndefine(State.prototype, 'toString', {\n value() {\n return ID.get(this.is);\n }\n});\n\ndefine(State, 'toString', {\n value() {\n return this.name;\n }\n});\n\n/** Register a user OnEvent callback, preserving `this` and `source`. */\nfunction callback<T extends State>(\n self: T,\n cb: Function,\n select?: Observer.Signal | Set<Observer.Signal>\n) {\n return listener(self, (key) => cb.call(self, key, self), select);\n}\n\n/**\n * Apply state arguemnts, run callbacks and observe properties.\n * Accumulate and handle cleanup events.\n **/\nfunction init(state: State, ...args: State.Args) {\n const T = state.constructor as State.Extends;\n\n if (T === State) throw new Error('Cannot create base State.');\n\n const { before, after } = bootstrap(T);\n\n ID.set(state, `${T}-${uid()}`);\n STORE.set(state, {});\n\n function observe() {\n for (const key in state) {\n const desc: PropertyDescriptor = Object.getOwnPropertyDescriptor(state, key) || {};\n\n if ('value' in desc && desc.configurable) apply(state, key, desc, true);\n }\n }\n\n function register() {\n if (Context.get(state) !== Context.root) return;\n\n const type = state.constructor as typeof State;\n const g = type.global;\n\n if (!(typeof g == 'function' ? g(state) : g)) return;\n\n if (!Object.prototype.hasOwnProperty.call(type, 'global'))\n throw new Error(\n `${state} would register as a global by inheritance alone - re-declare \\`static global\\` on ${type.name} (\\`true\\` to keep it, \\`false\\` to opt out).`\n );\n\n return Context.root.add(state);\n }\n\n listener(state, (key) => {\n const rest = trailing(state);\n\n PENDING.delete(state);\n\n if (key === null) return null;\n\n parent(state, null);\n\n const queue = [...before, observe, ...args, ...after, register];\n\n capture((release) => {\n listener(state, () => release(null), null);\n\n for (let i = 0; i < queue.length; i++) {\n const arg = queue[i];\n const out = typeof arg == 'function' ? arg.call(state, state) : arg;\n\n if (out instanceof Promise)\n out.catch((err) => {\n console.error(`Async error in constructor for ${state}:`);\n console.error(err);\n });\n else if (Array.isArray(out)) queue.splice(i + 1, 0, ...out);\n else if (typeof out == 'function') listener(state, out, null);\n else if (typeof out == 'object') assign(state, out, true);\n }\n });\n\n let end = rest.length;\n\n while (end-- > 0 && PENDING.has(rest[end]));\n\n for (let i = 0; i < end; i++) PENDING.delete(rest[i]);\n\n return null;\n });\n\n if (!QUEUED) {\n QUEUED = true;\n\n queueMicrotask(() => {\n QUEUED = false;\n\n for (const item of PENDING)\n if (typeof item == 'function') item();\n else console.warn(`${item} was constructed but never activated.`);\n\n PENDING.clear();\n });\n }\n\n PENDING.add(state);\n}\n\n/**\n * Apply instructions and inherited event listeners. Ensure class metadata is ready.\n *\n * @param T - State class to bootstrap.\n * @return Array of init functions to run on instance, in order of class hierarchy.\n */\nfunction bootstrap(T: State.Extends) {\n const chain = [] as State.Extends[];\n const before = new Set<State.Init>();\n const after = new Set<State.Init>();\n const onType = new Set<NonNullable<State.On['type']>>();\n let keys = new Map<string, (value: any) => void>();\n let getters = new Map<string, () => unknown>();\n\n while (true) {\n chain.unshift(T);\n if (T === State) break;\n T = Object.getPrototypeOf(T);\n }\n\n for (const type of chain) {\n for (const handler of SETUP.get(type) || [])\n if (typeof handler == 'function') before.add(handler);\n else {\n if (handler.before) before.add(handler.before);\n if (handler.after) after.add(handler.after);\n if (handler.type) onType.add(handler.type);\n }\n\n if (type === State) continue;\n\n if (METHODS.has(type)) {\n keys = METHODS.get(type)!;\n getters = GETTERS.get(type)!;\n continue;\n }\n\n for (const setupType of onType) setupType(type);\n\n METHODS.set(type, (keys = new Map(keys)));\n GETTERS.set(type, (getters = new Map(getters)));\n\n for (const [key, desc] of Object.entries(\n Object.getOwnPropertyDescriptors(type.prototype)\n )) {\n if (key == 'constructor' || !desc.configurable) continue;\n\n if (typeof desc.get == 'function') {\n if (desc.configurable && typeof desc.set != 'function')\n getters.set(key, desc.get);\n\n continue;\n }\n\n const { value } = desc;\n\n if (typeof value !== 'function') continue;\n\n function bind(this: State, original?: Function) {\n const { is } = this;\n\n if (is.hasOwnProperty(key) && !original) return value as Function;\n\n const fn = original || value;\n const bound = fn.bind(is);\n\n UNBIND.set(bound, fn);\n define(is, key, { value: bound, writable: true, configurable: true });\n\n return bound;\n }\n\n UNBIND.set(bind, value);\n\n keys.set(key, bind);\n define(type.prototype, key, { get: bind, set: bind });\n }\n }\n\n if (getters.size)\n before.add((self) => getters.forEach(compute, self));\n\n return { before, after };\n}\n\n/**\n * Install a reactive computed property on a state instance, derived from a prototype\n * getter or an arity-bearing `set` factory.\n *\n * The getter is invoked with the tracking proxy as both `this` and its first argument;\n * reads of managed properties through it create subscriptions. Result is cached and\n * emits a keyed event when stale.\n */\nfunction compute(this: State, getter: (self: any) => unknown, key: string) {\n const store = STORE.get(this)!;\n let reset: (() => void) | undefined;\n let isAsync: boolean;\n let proxy: any;\n\n const connect = () => {\n reset = watch(\n this,\n (current) => {\n proxy = current;\n\n if (!(key in store) || STALE.delete(run)) run(!reset);\n\n return (didUpdate) => {\n if (didUpdate) {\n STALE.add(run);\n event(this, key, true);\n }\n };\n },\n false\n );\n };\n\n const run = (initial?: boolean) => {\n let next: unknown;\n\n try {\n next = getter.call(proxy, proxy);\n } catch (err) {\n console.warn(\n `An exception was thrown while ${initial ? 'initializing' : 'refreshing'\n } ${this}.${key}.`\n );\n\n if (initial) throw err;\n\n console.error(err);\n }\n\n update(this, key, next, !isAsync);\n };\n\n apply(\n this,\n key,\n {\n enumerable: true,\n set: false,\n get: () => {\n if (!proxy) {\n if (observer(this) === null) return store[key];\n\n connect();\n isAsync = true;\n }\n\n if (STALE.delete(run)) run();\n\n return access(this, key, !proxy);\n }\n },\n true\n );\n}\n\n/**\n * Define or update a managed property using a descriptor config.\n * If the property already is managed, config will only accept value.\n * If the property does not exist, it will be created and made reactive.\n *\n * @param state - State to apply property to.\n * @param key - Property to define or update.\n * @param config - Descriptor config with value, get, set, enumerable, and/or destroy.\n * @param silent - If an update does occur, listeners will not be refreshed automatically.\n */\nfunction apply(\n state: State,\n key: string,\n config: State.Apply,\n silent?: boolean\n) {\n const desc = Object.getOwnPropertyDescriptor(state, key);\n\n if (desc && 'get' in desc) {\n if (Object.keys(config).some((k) => k != 'value'))\n throw new Error(`Property ${key} on ${state} is already defined.`);\n if ('value' in config) update(state, key, config.value, silent);\n return;\n }\n\n function set(value: unknown, silent?: boolean) {\n update(state, key, value, silent, true);\n }\n\n define(state, key, {\n configurable: true,\n enumerable: config.enumerable !== false,\n get(this: State) {\n const value =\n typeof config.get == 'function'\n ? config.get(this)\n : access(state, key, config.get);\n\n return touch(this, key, value);\n },\n set(next: any, silent?: boolean) {\n if (config.set === false)\n throw new Error(`${state}.${String(key)} is read-only.`);\n\n if (typeof config.set == 'function')\n try {\n const output = config.set(next, STORE.get(state)![key]);\n if (output !== undefined) next = output;\n } catch (err: unknown) {\n if (err === false) return;\n if (err === true) {\n set(next, true);\n return;\n }\n throw err;\n }\n\n set(next, silent);\n }\n });\n\n if ('value' in config) set(config.value, silent);\n}\n\nfunction provides(ctx: Context, value: State) {\n while (ctx = ctx.parent!) {\n const entries = ctx.provide.get(value.constructor as State.Extends);\n if (entries) for (const [state] of entries) if (state === value) return true;\n }\n}\n\nfunction child(state: State) {\n let cleanup: (() => void) | undefined;\n const ctx = Context.get(state);\n\n function reset() {\n if (cleanup) cleanup();\n cleanup = undefined;\n }\n\n listener(state, reset, null);\n\n return (value: unknown) => {\n reset();\n\n if (!(value instanceof State)) return;\n\n if (parent(value, state)) {\n const remove = join(state, value);\n cleanup = () => {\n cancel();\n remove();\n event(value, null);\n };\n const cancel = listener(state, cleanup, null);\n } else if (!provides(ctx, value)) {\n cleanup = join(state, value);\n }\n\n event(value);\n\n CHILDREN.get(state)?.forEach((cb) => cb(value));\n };\n}\n\n/**\n * Pending States constructed after this one - in a parent, the products of\n * its own initializers, until the last one it kept.\n */\nfunction trailing(state: State) {\n const rest: State[] = [];\n let seen = false;\n\n for (const item of PENDING)\n if (!seen) seen = item === state;\n else if (item instanceof State) rest.push(item);\n\n return rest;\n}\n\n/**\n * Report States adopted by a parent - those already held, then each one\n * claimed later. Returns a callback to stop watching.\n */\nfunction children(state: State, callback: (child: State) => void) {\n const store = STORE.get(state)!;\n const keys = ADOPT.get(state);\n\n if (keys)\n for (const key of keys.keys()) {\n const value = store[key as string];\n if (value instanceof State) callback(value);\n }\n\n let set = CHILDREN.get(state);\n\n if (!set) CHILDREN.set(state, (set = new Set()));\n\n set.add(callback);\n\n return () => set!.delete(callback);\n}\n\n/** Currently accumulating export. Stores real values of placeholder properties such as ref() or child states. */\nlet EXPORT: Map<any, any> | undefined;\n\nfunction values<T extends State>(state: T): State.Values<T> {\n const values = {} as any;\n let notRecursive;\n\n if (!EXPORT) {\n notRecursive = true;\n EXPORT = new Map();\n }\n\n EXPORT.set(state, values);\n\n for (let [key, value] of state) {\n if (EXPORT.has(value)) value = EXPORT.get(value);\n else if (\n value &&\n typeof value == 'object' &&\n 'get' in value &&\n typeof value.get === 'function'\n )\n value = value.get();\n\n values[key] = value;\n }\n\n if (notRecursive) EXPORT = undefined;\n\n return Object.freeze(values);\n}\n\nfunction access(state: State, property: string, required?: boolean) {\n const store = STORE.get(state)!;\n\n if (property in store || required === false) {\n const value = store[property];\n\n if (value !== undefined || !required) return value;\n }\n\n if (METHODS.get(state.constructor)!.has(property))\n return unbind((state as any)[property]);\n\n if (observer(state) === null) return undefined;\n\n const error = new Error(`${state}.${property} is not yet available.`);\n const promise = new Promise<any>((resolve, reject) => {\n listener(state, (key) => {\n if (key === property) {\n resolve(store[key]);\n return null;\n }\n\n if (key === null) {\n reject(new Error(`${state} is destroyed.`));\n }\n });\n });\n\n throw Object.assign(promise, {\n toString: () => String(error),\n name: 'Suspense',\n message: error.message,\n stack: error.stack\n });\n}\n\nfunction assign(state: State, data: State.Assign<State>, silent?: boolean) {\n if (!silent) event(state);\n\n const methods = METHODS.get(state.constructor)!;\n const getters = GETTERS.get(state.constructor);\n\n for (const key in data) {\n const bind = methods.get(key);\n\n if (bind) bind.call(state, data[key]);\n else if (getters?.has(key)) continue;\n else if (key in state && key !== 'is') {\n const desc: PropertyDescriptor = Object.getOwnPropertyDescriptor(state, key) || {};\n const set = desc.set as (value: any, silent?: boolean) => void;\n\n if (set) {\n set.call(state, data[key], silent);\n } else {\n (state as any)[key] = data[key];\n }\n }\n }\n}\n\n/**\n * Update a property on a state instance and notify listeners.\n *\n * 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.\n *\n * If `silent` is true, the update will not dispatch events and will return `false` instead of throwing if state is destroyed.\n */\nfunction update<T>(\n state: State,\n key: State.Event<T>,\n value: T,\n silent?: boolean,\n own?: boolean\n) {\n if (observer(state) === null) {\n if (silent) return false;\n throw new Error(\n `Tried to update ${state}.${String(key)} but state is destroyed.`\n );\n }\n\n const store = STORE.get(state)!;\n\n if (value instanceof State) value = value.is as T;\n\n if (key in store && value === store[key]) return false;\n\n store[key] = value;\n\n if (!silent) event(state, key);\n\n if (own) adopt(state, key, value);\n\n return true;\n}\n\n/**\n * Hand a value stored by an owning writer to that property's adopter,\n * creating one the first time a State is stored there. A property which has\n * held a State keeps its adopter, so a later non-State value releases the\n * previous child.\n */\nfunction adopt(state: State, key: unknown, value: unknown) {\n let keys = ADOPT.get(state);\n\n if (!keys) {\n if (!(value instanceof State)) return;\n ADOPT.set(state, (keys = new Map()));\n }\n\n let claim = keys.get(key);\n\n if (!claim) {\n if (!(value instanceof State)) return;\n keys.set(key, (claim = child(state)));\n }\n\n claim(value);\n}\n\n/** Random alphanumberic of length 6; always starts with a letter. */\nfunction uid() {\n return (0.278 + Math.random() * 0.722)\n .toString(36)\n .substring(2, 8)\n .toUpperCase();\n}\n\nfunction unbind<T extends Function>(fn: T): T;\nfunction unbind<T extends Function>(fn?: T): T | undefined;\nfunction unbind(fn?: Function) {\n return UNBIND.get(fn) || fn;\n}\n\n/**\n * Read or claim a parent for a given child. In read mode (one argument) returns\n * the current parent, or `undefined` if never assigned. In write mode assigns\n * only if unclaimed and returns whether the assignment applied - `true` means\n * this call freshly claimed it, `false` means it was already parented.\n */\nfunction parent(child: object): State | null | undefined;\nfunction parent(child: object, value: State | null): boolean;\nfunction parent(child: object, value?: State | null) {\n if (arguments.length < 2) return PARENT.get(child as State);\n if (PARENT.has(child as State)) return false;\n PARENT.set(child as State, value ?? null);\n return true;\n}\n\nexport { event, unbind, State, parent, children, PENDING, STORE, uid, access, update, apply, compute };\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@expressive/mvc",
3
- "version": "0.84.3",
3
+ "version": "0.85.0",
4
4
  "description": "Class-based reactive state management - framework-agnostic core of Expressive MVC.",
5
5
  "sideEffects": false,
6
6
  "keywords": [