@expressive/mvc 0.85.0 → 0.87.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/caught.js ADDED
@@ -0,0 +1,64 @@
1
+ //#region src/caught.ts
2
+ const about = (cause) => {
3
+ const text = cause instanceof Error ? cause.message : String(cause);
4
+ return text ? `: ${text}` : ".";
5
+ };
6
+ /**
7
+ * Reported to `State.on({ catch })` handlers instead of being thrown or logged.
8
+ * Unhandled, a `warning` goes to `console.warn`; anything else escapes uncaught.
9
+ */
10
+ var Caught = class Caught extends Error {
11
+ name = "Caught";
12
+ /** Non-urgent - unhandled, it logs as a warning. */
13
+ warning = false;
14
+ constructor(state, message, key, cause) {
15
+ super(message, arguments.length > 3 ? { cause } : void 0);
16
+ this.key = key;
17
+ Object.defineProperty(this, "state", { value: state });
18
+ }
19
+ /** A `catch` handler logging what would otherwise escape uncaught; warnings and destroyed writes pass on. */
20
+ static log(error) {
21
+ if (error.warning || error instanceof Caught.Destroyed) return error;
22
+ console.error(error);
23
+ }
24
+ /** A write to a destroyed state - thrown to the writer unless a handler takes it. */
25
+ static Destroyed = class Destroyed extends Caught {
26
+ name = "Caught.Destroyed";
27
+ constructor(state, key) {
28
+ super(state, `Tried to update ${state}.${key} but state is destroyed.`, key);
29
+ }
30
+ };
31
+ /** A state constructed but never activated. */
32
+ static Inactive = class Inactive extends Caught {
33
+ name = "Caught.Inactive";
34
+ warning = true;
35
+ constructor(state) {
36
+ super(state, `${state} was constructed but never activated.`);
37
+ }
38
+ };
39
+ /** A getter threw while refreshing; `cause` is what it threw. */
40
+ static Getter = class Getter extends Caught {
41
+ name = "Caught.Getter";
42
+ constructor(state, key, cause) {
43
+ super(state, `An exception was thrown while refreshing ${state.constructor}.${key}${about(cause)}`, key, cause);
44
+ }
45
+ };
46
+ /** An async initializer rejected; `cause` is the rejection. */
47
+ static Init = class Init extends Caught {
48
+ name = "Caught.Init";
49
+ constructor(state, cause) {
50
+ super(state, `Async error in constructor for ${state.constructor}${about(cause)}`, void 0, cause);
51
+ }
52
+ };
53
+ /** An effect or listener threw during a dispatch flush; `cause` is what it threw. */
54
+ static Effect = class Effect extends Caught {
55
+ name = "Caught.Effect";
56
+ constructor(state, cause) {
57
+ super(state, `An exception was thrown by an effect of ${state.constructor}${about(cause)}`, void 0, cause);
58
+ }
59
+ };
60
+ };
61
+
62
+ //#endregion
63
+ export { Caught };
64
+ //# sourceMappingURL=caught.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"caught.js","names":[],"sources":["../src/caught.ts"],"sourcesContent":["import type { State } from './state';\n\nconst about = (cause: unknown) => {\n const text = cause instanceof Error ? cause.message : String(cause);\n return text ? `: ${text}` : '.';\n};\n\n/**\n * Reported to `State.on({ catch })` handlers instead of being thrown or logged.\n * Unhandled, a `warning` goes to `console.warn`; anything else escapes uncaught.\n */\nclass Caught extends Error {\n readonly name: string = 'Caught';\n\n /** Non-urgent - unhandled, it logs as a warning. */\n readonly warning: boolean = false;\n\n declare readonly state: State;\n\n constructor(\n state: State,\n message: string,\n readonly key?: string,\n cause?: unknown\n ) {\n super(message, arguments.length > 3 ? { cause } : undefined);\n Object.defineProperty(this, 'state', { value: state });\n }\n\n /** A `catch` handler logging what would otherwise escape uncaught; warnings and destroyed writes pass on. */\n static log(error: Caught): Caught | void {\n if (error.warning || error instanceof Caught.Destroyed) return error;\n console.error(error);\n }\n\n /** A write to a destroyed state - thrown to the writer unless a handler takes it. */\n static Destroyed = class Destroyed extends Caught {\n readonly name = 'Caught.Destroyed';\n\n constructor(state: State, key: string) {\n super(state, `Tried to update ${state}.${key} but state is destroyed.`, key);\n }\n };\n\n /** A state constructed but never activated. */\n static Inactive = class Inactive extends Caught {\n readonly name = 'Caught.Inactive';\n readonly warning = true;\n\n constructor(state: State) {\n super(state, `${state} was constructed but never activated.`);\n }\n };\n\n /** A getter threw while refreshing; `cause` is what it threw. */\n static Getter = class Getter extends Caught {\n readonly name = 'Caught.Getter';\n\n constructor(state: State, key: string, cause: unknown) {\n super(state, `An exception was thrown while refreshing ${state.constructor}.${key}${about(cause)}`, key, cause);\n }\n };\n\n /** An async initializer rejected; `cause` is the rejection. */\n static Init = class Init extends Caught {\n readonly name = 'Caught.Init';\n\n constructor(state: State, cause: unknown) {\n super(state, `Async error in constructor for ${state.constructor}${about(cause)}`, undefined, cause);\n }\n };\n\n /** An effect or listener threw during a dispatch flush; `cause` is what it threw. */\n static Effect = class Effect extends Caught {\n readonly name = 'Caught.Effect';\n\n constructor(state: State, cause: unknown) {\n super(state, `An exception was thrown by an effect of ${state.constructor}${about(cause)}`, undefined, cause);\n }\n };\n}\n\ndeclare namespace Caught {\n type Destroyed = InstanceType<typeof Caught.Destroyed>;\n type Inactive = InstanceType<typeof Caught.Inactive>;\n type Getter = InstanceType<typeof Caught.Getter>;\n type Init = InstanceType<typeof Caught.Init>;\n type Effect = InstanceType<typeof Caught.Effect>;\n}\n\nexport { Caught };\n"],"mappings":";AAEA,MAAM,SAAS,UAAmB;CAChC,MAAM,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACnE,QAAO,OAAO,KAAK,SAAS;;;;;;AAO9B,IAAM,SAAN,MAAM,eAAe,MAAM;CACzB,AAAS,OAAe;;CAGxB,AAAS,UAAmB;CAI5B,YACE,OACA,SACA,AAAS,KACT,OACA;AACA,QAAM,SAAS,UAAU,SAAS,IAAI,EAAE,OAAO,GAAG,OAAU;EAHnD;AAIT,SAAO,eAAe,MAAM,SAAS,EAAE,OAAO,OAAO,CAAC;;;CAIxD,OAAO,IAAI,OAA8B;AACvC,MAAI,MAAM,WAAW,iBAAiB,OAAO,UAAW,QAAO;AAC/D,UAAQ,MAAM,MAAM;;;CAItB,OAAO,YAAY,MAAM,kBAAkB,OAAO;EAChD,AAAS,OAAO;EAEhB,YAAY,OAAc,KAAa;AACrC,SAAM,OAAO,mBAAmB,MAAM,GAAG,IAAI,2BAA2B,IAAI;;;;CAKhF,OAAO,WAAW,MAAM,iBAAiB,OAAO;EAC9C,AAAS,OAAO;EAChB,AAAS,UAAU;EAEnB,YAAY,OAAc;AACxB,SAAM,OAAO,GAAG,MAAM,uCAAuC;;;;CAKjE,OAAO,SAAS,MAAM,eAAe,OAAO;EAC1C,AAAS,OAAO;EAEhB,YAAY,OAAc,KAAa,OAAgB;AACrD,SAAM,OAAO,4CAA4C,MAAM,YAAY,GAAG,MAAM,MAAM,MAAM,IAAI,KAAK,MAAM;;;;CAKnH,OAAO,OAAO,MAAM,aAAa,OAAO;EACtC,AAAS,OAAO;EAEhB,YAAY,OAAc,OAAgB;AACxC,SAAM,OAAO,kCAAkC,MAAM,cAAc,MAAM,MAAM,IAAI,QAAW,MAAM;;;;CAKxG,OAAO,SAAS,MAAM,eAAe,OAAO;EAC1C,AAAS,OAAO;EAEhB,YAAY,OAAc,OAAgB;AACxC,SAAM,OAAO,2CAA2C,MAAM,cAAc,MAAM,MAAM,IAAI,QAAW,MAAM"}
@@ -87,6 +87,8 @@ declare class Component extends State {
87
87
  */
88
88
  catch?(error: Error): Promise<void> | void;
89
89
  }
90
+ /** Drop composed renders, so each is rebuilt from current prototypes. */
91
+ declare function rechain(): void;
90
92
  //#endregion
91
- export { Component };
93
+ export { Component, rechain };
92
94
  //# sourceMappingURL=component.d.ts.map
package/dist/component.js CHANGED
@@ -1,11 +1,11 @@
1
- import { State, unbind } from "./state.js";
1
+ import { State, trailing, unbind } from "./state.js";
2
2
  import { Context } from "./context.js";
3
3
  import { set } from "./field/set.js";
4
4
 
5
5
  //#region src/component.ts
6
6
  const PENDING = /* @__PURE__ */ new WeakMap();
7
7
  /** Per-class composed content render. */
8
- const CHAIN = /* @__PURE__ */ new WeakMap();
8
+ let CHAIN = /* @__PURE__ */ new WeakMap();
9
9
  var Component = class extends State {
10
10
  /**
11
11
  * Content to display while this component or its children are suspended.
@@ -20,7 +20,7 @@ var Component = class extends State {
20
20
  constructor(props, ...rest) {
21
21
  if (props == null) props = {};
22
22
  const seen = {};
23
- const copy = PENDING.get(props);
23
+ const twin = PENDING.get(props);
24
24
  if (typeof props == "object") merge(props);
25
25
  function merge(props) {
26
26
  for (const k in props) seen[k] = void 0;
@@ -29,28 +29,32 @@ var Component = class extends State {
29
29
  ...props
30
30
  };
31
31
  }
32
- super(copy ? [] : [
32
+ super([
33
33
  props,
34
34
  rest.filter((x) => !(x instanceof Context)),
35
35
  () => {
36
+ const other = twin || PENDING.get(props);
37
+ if (other !== this) {
38
+ trailing(other).forEach((orphan) => orphan.set(null));
39
+ other.set(null);
40
+ }
36
41
  props.is?.(this);
37
42
  Object.defineProperty(this, "props", { enumerable: false });
38
43
  PENDING.delete(props);
39
44
  }
40
45
  ]);
41
- if (copy) {
42
- this.set(null);
43
- return copy;
44
- }
45
46
  PENDING.set(props, this);
46
47
  this.props = props;
47
48
  this.set("props", () => {
48
49
  this.set(merge(this.props));
49
50
  });
51
+ const self = this;
50
52
  Object.defineProperty(this, "render", {
51
53
  writable: true,
52
54
  configurable: true,
53
- value: render(this)
55
+ value(props) {
56
+ return render(self).call(this, props);
57
+ }
54
58
  });
55
59
  }
56
60
  /**
@@ -137,7 +141,11 @@ function compose(outer, inner) {
137
141
  });
138
142
  };
139
143
  }
144
+ /** Drop composed renders, so each is rebuilt from current prototypes. */
145
+ function rechain() {
146
+ CHAIN = /* @__PURE__ */ new WeakMap();
147
+ }
140
148
 
141
149
  //#endregion
142
- export { Component };
150
+ export { Component, rechain };
143
151
  //# sourceMappingURL=component.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"component.js","names":[],"sources":["../src/component.ts"],"sourcesContent":["import { Context } from './context';\nimport { set } from './field/set';\nimport { State, unbind } from './state';\n\nimport type { Host } from './runtime';\n\nconst PENDING = new WeakMap<object, Component>();\n\n/** Per-class composed content render. */\nconst CHAIN = new WeakMap<Function, Function>();\n\ntype IfEquals<X, Y, A, B> =\n (<T>() => T extends X ? 1 : 2) extends\n (<T>() => T extends Y ? 1 : 2) ? A : B;\n\n/** Keys of T which are settable (excludes get-only accessors and `readonly`). */\ntype Acceptable<T> = {\n [P in keyof T]-?: IfEquals<\n { [Q in P]: T[P] },\n { -readonly [Q in P]: T[P] },\n P, never\n >;\n}[keyof T];\n\ndeclare namespace Component {\n /**\n * Host element type produced by `Component.render`. Delegates to the\n * {@link Host} manifest on the jsx-runtime entry; falls back to `any`\n * until an adapter augments it with `node`. `any` (not `unknown`) so an\n * un-annotated `render` override in a host-agnostic package still emits a\n * JSX-valid return - `any` is assignable to every host's node type, where\n * `unknown` is assignable to none.\n */\n type Node = Host extends { node: infer T } ? T : any;\n\n interface BaseProps<T extends Component> {\n /**\n * Callback for newly created instance. Only called once.\n *\n * Runs after props apply but **before** the `new()` lifecycle hook - so it\n * may configure state that `new()` then observes. To react to a fully\n * initialized instance instead, use `watch` or an effect.\n */\n is?: (instance: T) => void;\n\n /**\n * Fallback to show when suspended or in error recovery.\n * Pass `false` to opt out of the component's own suspense boundary,\n * letting suspension bubble to an ancestor.\n */\n fallback?: Component.Node;\n }\n\n type StateProps<T extends State> = {\n [K in Exclude<keyof T, keyof Component> & Acceptable<T>]?: T[K];\n };\n\n type RenderProps<T> = [T] extends [(props: infer P) => any]\n ? [keyof NonNullable<P>] extends [never]\n ? { children?: Component.Node }\n : NonNullable<P>\n : { children?: Component.Node };\n\n type Props<T extends Component> =\n & StateProps<T>\n & BaseProps<T>\n & RenderProps<T['render']>;\n}\n\nclass Component extends State {\n /**\n * All JSX attributes passed to this component.\n * Includes state-derived props, render props, and built-in props like `is` and `fallback`.\n *\n * Will incorperate extra props you declare as props parameter in `render` method.\n */\n declare readonly props: Component.Props<this>;\n\n /** Stable identity used when this instance is rendered in a collection. */\n declare readonly key: string;\n\n /**\n * Content to display while this component or its children are suspended.\n * Will cover suspense by pending properties in `this.render` as well.\n * Can be set as a class property or overridden via the `fallback` JSX prop.\n *\n * Defaults to null - nothing will be rendered.\n * Set `false` to opt out of having a boundary at all - suspension then\n * bubbles to the nearest ancestor boundary.\n */\n fallback: Component.Node = set(null);\n\n constructor(props?: any, ...rest: any[]) {\n if (props == null) props = {};\n\n const seen = {} as Record<string, undefined>;\n const copy = PENDING.get(props);\n\n if (typeof props == 'object') merge(props);\n\n function merge(props: {}) {\n for (const k in props) seen[k] = undefined;\n return { ...seen, ...props };\n }\n\n super(copy ? [] : [\n props,\n rest.filter((x) => !(x instanceof Context)),\n () => {\n props.is?.(this);\n Object.defineProperty(this, 'props', { enumerable: false });\n PENDING.delete(props);\n }\n ]);\n\n if (copy) {\n this.set(null);\n return copy;\n }\n\n PENDING.set(props, this);\n\n this.props = props;\n this.set('props', () => {\n this.set(merge(this.props));\n });\n\n Object.defineProperty(this, 'render', {\n writable: true,\n configurable: true,\n value: render(this)\n });\n }\n\n /**\n * Output for this component. Override to define custom JSX.\n *\n * Properties accessed via `this` are reactive and trigger a render when they\n * change, in addition to props. Accepts an optional parameter to receive extra\n * props from JSX, beyond those merged to state properties; declare its shape\n * via `props = {} as { ... }`. Without a parameter (the default below),\n * children pass through.\n *\n * The constructor installs a composed `render` per instance; the bootstrap\n * `type` pass seals this and any override non-configurable, keeping it the\n * content-render seam the chain reads.\n */\n render(props?: {}): Component.Node {\n const { children } = (props || this.props) as { children?: Component.Node };\n return children || null;\n }\n\n /**\n * Called when a child component throws during render.\n * While this is pending, `fallback` is displayed.\n * When resolved, the error boundary resets and `render` is called again.\n *\n * Override to handle errors - set `this.fallback` for error-specific UI,\n * await async recovery, or await user interaction before retrying. If you\n * assign a fallback within catch, it will be reverted after resolved.\n */\n catch?(error: Error): Promise<void> | void;\n}\n\n/**\n * Default `key` accessor. The get/set pair keeps it off observed state.\n */\nObject.defineProperty(Component.prototype, 'key', {\n configurable: true,\n get() {\n return String(this);\n },\n set(value) {\n Object.defineProperty(this, 'key', { value });\n }\n});\n\n/**\n * Seal each class's own `render` non-configurable at bootstrap so member\n * classification leaves it unbound - it stays the content-render seam the chain\n * reads (and which adapters like preact detect as the class-component marker).\n */\nComponent.on({\n before(self) {\n const key = Object.getOwnPropertyDescriptor(self, 'key');\n\n if (key?.configurable)\n Object.defineProperty(self, 'key', {\n enumerable: false,\n writable: false\n });\n },\n type(type) {\n const desc = Object.getOwnPropertyDescriptor(type.prototype, 'render');\n\n if (desc && typeof desc.value == 'function')\n Object.defineProperty(type.prototype, 'render', {\n ...desc,\n configurable: false\n });\n }\n});\n\n/**\n * Build (or fetch the cached) composed content render for an instance's class.\n * Walks the prototype chain for content renders strictly below Component - the\n * default render on Component.prototype is excluded and serves as the fallback\n * when a class authors none.\n */\nfunction render(target: Component) {\n const cached = CHAIN.get(target.constructor);\n\n if (cached) return cached;\n\n let render: Function | undefined;\n let proto = target;\n\n while ((proto = Object.getPrototypeOf(proto)) !== Component.prototype) {\n const desc = Object.getOwnPropertyDescriptor(proto, 'render');\n\n if (desc) {\n const layer = unbind(desc.get || desc.value);\n render = render ? compose(layer, render) : layer;\n }\n }\n\n if (!render)\n render = Component.prototype.render;\n\n CHAIN.set(target.constructor, render);\n\n return render;\n}\n\n/** Wrap an outer render so it receives `inner` as a lazy `children` getter. */\nfunction compose(outer: Function, inner: Function): Function {\n return function (this: Component, props?: {}) {\n const self = this;\n return outer.call(self, {\n ...props,\n get children() {\n return inner.call(self, props);\n }\n });\n };\n}\n\nexport { Component };\n"],"mappings":";;;;;AAMA,MAAM,0BAAU,IAAI,SAA4B;;AAGhD,MAAM,wBAAQ,IAAI,SAA6B;AA4D/C,IAAM,YAAN,cAAwB,MAAM;;;;;;;;;;CAqB5B,WAA2B,IAAI,KAAK;CAEpC,YAAY,OAAa,GAAG,MAAa;AACvC,MAAI,SAAS,KAAM,SAAQ,EAAE;EAE7B,MAAM,OAAO,EAAE;EACf,MAAM,OAAO,QAAQ,IAAI,MAAM;AAE/B,MAAI,OAAO,SAAS,SAAU,OAAM,MAAM;EAE1C,SAAS,MAAM,OAAW;AACxB,QAAK,MAAM,KAAK,MAAO,MAAK,KAAK;AACjC,UAAO;IAAE,GAAG;IAAM,GAAG;IAAO;;AAG9B,QAAM,OAAO,EAAE,GAAG;GAChB;GACA,KAAK,QAAQ,MAAM,EAAE,aAAa,SAAS;SACrC;AACJ,UAAM,KAAK,KAAK;AAChB,WAAO,eAAe,MAAM,SAAS,EAAE,YAAY,OAAO,CAAC;AAC3D,YAAQ,OAAO,MAAM;;GAExB,CAAC;AAEF,MAAI,MAAM;AACR,QAAK,IAAI,KAAK;AACd,UAAO;;AAGT,UAAQ,IAAI,OAAO,KAAK;AAExB,OAAK,QAAQ;AACb,OAAK,IAAI,eAAe;AACtB,QAAK,IAAI,MAAM,KAAK,MAAM,CAAC;IAC3B;AAEF,SAAO,eAAe,MAAM,UAAU;GACpC,UAAU;GACV,cAAc;GACd,OAAO,OAAO,KAAK;GACpB,CAAC;;;;;;;;;;;;;;;CAgBJ,OAAO,OAA4B;EACjC,MAAM,EAAE,aAAc,SAAS,KAAK;AACpC,SAAO,YAAY;;;;;;AAkBvB,OAAO,eAAe,UAAU,WAAW,OAAO;CAChD,cAAc;CACd,MAAM;AACJ,SAAO,OAAO,KAAK;;CAErB,IAAI,OAAO;AACT,SAAO,eAAe,MAAM,OAAO,EAAE,OAAO,CAAC;;CAEhD,CAAC;;;;;;AAOF,UAAU,GAAG;CACX,OAAO,MAAM;AAGX,MAFY,OAAO,yBAAyB,MAAM,MAAM,EAE/C,aACP,QAAO,eAAe,MAAM,OAAO;GACjC,YAAY;GACZ,UAAU;GACX,CAAC;;CAEN,KAAK,MAAM;EACT,MAAM,OAAO,OAAO,yBAAyB,KAAK,WAAW,SAAS;AAEtE,MAAI,QAAQ,OAAO,KAAK,SAAS,WAC/B,QAAO,eAAe,KAAK,WAAW,UAAU;GAC9C,GAAG;GACH,cAAc;GACf,CAAC;;CAEP,CAAC;;;;;;;AAQF,SAAS,OAAO,QAAmB;CACjC,MAAM,SAAS,MAAM,IAAI,OAAO,YAAY;AAE5C,KAAI,OAAQ,QAAO;CAEnB,IAAI;CACJ,IAAI,QAAQ;AAEZ,SAAQ,QAAQ,OAAO,eAAe,MAAM,MAAM,UAAU,WAAW;EACrE,MAAM,OAAO,OAAO,yBAAyB,OAAO,SAAS;AAE7D,MAAI,MAAM;GACR,MAAM,QAAQ,OAAO,KAAK,OAAO,KAAK,MAAM;AAC5C,YAAS,SAAS,QAAQ,OAAO,OAAO,GAAG;;;AAI/C,KAAI,CAAC,OACH,UAAS,UAAU,UAAU;AAE/B,OAAM,IAAI,OAAO,aAAa,OAAO;AAErC,QAAO;;;AAIT,SAAS,QAAQ,OAAiB,OAA2B;AAC3D,QAAO,SAA2B,OAAY;EAC5C,MAAM,OAAO;AACb,SAAO,MAAM,KAAK,MAAM;GACtB,GAAG;GACH,IAAI,WAAW;AACb,WAAO,MAAM,KAAK,MAAM,MAAM;;GAEjC,CAAC"}
1
+ {"version":3,"file":"component.js","names":[],"sources":["../src/component.ts"],"sourcesContent":["import { Context } from './context';\nimport { set } from './field/set';\nimport { State, trailing, unbind } from './state';\n\nimport type { Host } from './runtime';\n\nconst PENDING = new WeakMap<object, Component>();\n\n/** Per-class composed content render. */\nlet CHAIN = new WeakMap<Function, Function>();\n\ntype IfEquals<X, Y, A, B> =\n (<T>() => T extends X ? 1 : 2) extends\n (<T>() => T extends Y ? 1 : 2) ? A : B;\n\n/** Keys of T which are settable (excludes get-only accessors and `readonly`). */\ntype Acceptable<T> = {\n [P in keyof T]-?: IfEquals<\n { [Q in P]: T[P] },\n { -readonly [Q in P]: T[P] },\n P, never\n >;\n}[keyof T];\n\ndeclare namespace Component {\n /**\n * Host element type produced by `Component.render`. Delegates to the\n * {@link Host} manifest on the jsx-runtime entry; falls back to `any`\n * until an adapter augments it with `node`. `any` (not `unknown`) so an\n * un-annotated `render` override in a host-agnostic package still emits a\n * JSX-valid return - `any` is assignable to every host's node type, where\n * `unknown` is assignable to none.\n */\n type Node = Host extends { node: infer T } ? T : any;\n\n interface BaseProps<T extends Component> {\n /**\n * Callback for newly created instance. Only called once.\n *\n * Runs after props apply but **before** the `new()` lifecycle hook - so it\n * may configure state that `new()` then observes. To react to a fully\n * initialized instance instead, use `watch` or an effect.\n */\n is?: (instance: T) => void;\n\n /**\n * Fallback to show when suspended or in error recovery.\n * Pass `false` to opt out of the component's own suspense boundary,\n * letting suspension bubble to an ancestor.\n */\n fallback?: Component.Node;\n }\n\n type StateProps<T extends State> = {\n [K in Exclude<keyof T, keyof Component> & Acceptable<T>]?: T[K];\n };\n\n type RenderProps<T> = [T] extends [(props: infer P) => any]\n ? [keyof NonNullable<P>] extends [never]\n ? { children?: Component.Node }\n : NonNullable<P>\n : { children?: Component.Node };\n\n type Props<T extends Component> =\n & StateProps<T>\n & BaseProps<T>\n & RenderProps<T['render']>;\n}\n\nclass Component extends State {\n /**\n * All JSX attributes passed to this component.\n * Includes state-derived props, render props, and built-in props like `is` and `fallback`.\n *\n * Will incorperate extra props you declare as props parameter in `render` method.\n */\n declare readonly props: Component.Props<this>;\n\n /** Stable identity used when this instance is rendered in a collection. */\n declare readonly key: string;\n\n /**\n * Content to display while this component or its children are suspended.\n * Will cover suspense by pending properties in `this.render` as well.\n * Can be set as a class property or overridden via the `fallback` JSX prop.\n *\n * Defaults to null - nothing will be rendered.\n * Set `false` to opt out of having a boundary at all - suspension then\n * bubbles to the nearest ancestor boundary.\n */\n fallback: Component.Node = set(null);\n\n constructor(props?: any, ...rest: any[]) {\n if (props == null) props = {};\n\n const seen = {} as Record<string, undefined>;\n const twin = PENDING.get(props);\n\n if (typeof props == 'object') merge(props);\n\n function merge(props: {}) {\n for (const k in props) seen[k] = undefined;\n return { ...seen, ...props };\n }\n\n super([\n props,\n rest.filter((x) => !(x instanceof Context)),\n () => {\n const other = twin || PENDING.get(props)!;\n\n if (other !== this) {\n trailing(other).forEach((orphan) => orphan.set(null));\n other.set(null);\n }\n\n props.is?.(this);\n Object.defineProperty(this, 'props', { enumerable: false });\n PENDING.delete(props);\n }\n ]);\n\n PENDING.set(props, this);\n\n this.props = props;\n this.set('props', () => {\n this.set(merge(this.props));\n });\n\n const self = this;\n\n Object.defineProperty(this, 'render', {\n writable: true,\n configurable: true,\n value(this: Component, props?: {}) {\n return render(self).call(this, props);\n }\n });\n }\n\n /**\n * Output for this component. Override to define custom JSX.\n *\n * Properties accessed via `this` are reactive and trigger a render when they\n * change, in addition to props. Accepts an optional parameter to receive extra\n * props from JSX, beyond those merged to state properties; declare its shape\n * via `props = {} as { ... }`. Without a parameter (the default below),\n * children pass through.\n *\n * The constructor installs a composed `render` per instance; the bootstrap\n * `type` pass seals this and any override non-configurable, keeping it the\n * content-render seam the chain reads.\n */\n render(props?: {}): Component.Node {\n const { children } = (props || this.props) as { children?: Component.Node };\n return children || null;\n }\n\n /**\n * Called when a child component throws during render.\n * While this is pending, `fallback` is displayed.\n * When resolved, the error boundary resets and `render` is called again.\n *\n * Override to handle errors - set `this.fallback` for error-specific UI,\n * await async recovery, or await user interaction before retrying. If you\n * assign a fallback within catch, it will be reverted after resolved.\n */\n catch?(error: Error): Promise<void> | void;\n}\n\n/**\n * Default `key` accessor. The get/set pair keeps it off observed state.\n */\nObject.defineProperty(Component.prototype, 'key', {\n configurable: true,\n get() {\n return String(this);\n },\n set(value) {\n Object.defineProperty(this, 'key', { value });\n }\n});\n\n/**\n * Seal each class's own `render` non-configurable at bootstrap so member\n * classification leaves it unbound - it stays the content-render seam the chain\n * reads (and which adapters like preact detect as the class-component marker).\n */\nComponent.on({\n before(self) {\n const key = Object.getOwnPropertyDescriptor(self, 'key');\n\n if (key?.configurable)\n Object.defineProperty(self, 'key', {\n enumerable: false,\n writable: false\n });\n },\n type(type) {\n const desc = Object.getOwnPropertyDescriptor(type.prototype, 'render');\n\n if (desc && typeof desc.value == 'function')\n Object.defineProperty(type.prototype, 'render', {\n ...desc,\n configurable: false\n });\n }\n});\n\n/**\n * Build (or fetch the cached) composed content render for an instance's class.\n * Walks the prototype chain for content renders strictly below Component - the\n * default render on Component.prototype is excluded and serves as the fallback\n * when a class authors none.\n */\nfunction render(target: Component) {\n const cached = CHAIN.get(target.constructor);\n\n if (cached) return cached;\n\n let render: Function | undefined;\n let proto = target;\n\n while ((proto = Object.getPrototypeOf(proto)) !== Component.prototype) {\n const desc = Object.getOwnPropertyDescriptor(proto, 'render');\n\n if (desc) {\n const layer = unbind(desc.get || desc.value);\n render = render ? compose(layer, render) : layer;\n }\n }\n\n if (!render)\n render = Component.prototype.render;\n\n CHAIN.set(target.constructor, render);\n\n return render;\n}\n\n/** Wrap an outer render so it receives `inner` as a lazy `children` getter. */\nfunction compose(outer: Function, inner: Function): Function {\n return function (this: Component, props?: {}) {\n const self = this;\n return outer.call(self, {\n ...props,\n get children() {\n return inner.call(self, props);\n }\n });\n };\n}\n\n/** Drop composed renders, so each is rebuilt from current prototypes. */\nfunction rechain() {\n CHAIN = new WeakMap();\n}\n\nexport { Component, rechain };\n"],"mappings":";;;;;AAMA,MAAM,0BAAU,IAAI,SAA4B;;AAGhD,IAAI,wBAAQ,IAAI,SAA6B;AA4D7C,IAAM,YAAN,cAAwB,MAAM;;;;;;;;;;CAqB5B,WAA2B,IAAI,KAAK;CAEpC,YAAY,OAAa,GAAG,MAAa;AACvC,MAAI,SAAS,KAAM,SAAQ,EAAE;EAE7B,MAAM,OAAO,EAAE;EACf,MAAM,OAAO,QAAQ,IAAI,MAAM;AAE/B,MAAI,OAAO,SAAS,SAAU,OAAM,MAAM;EAE1C,SAAS,MAAM,OAAW;AACxB,QAAK,MAAM,KAAK,MAAO,MAAK,KAAK;AACjC,UAAO;IAAE,GAAG;IAAM,GAAG;IAAO;;AAG9B,QAAM;GACJ;GACA,KAAK,QAAQ,MAAM,EAAE,aAAa,SAAS;SACrC;IACJ,MAAM,QAAQ,QAAQ,QAAQ,IAAI,MAAM;AAExC,QAAI,UAAU,MAAM;AAClB,cAAS,MAAM,CAAC,SAAS,WAAW,OAAO,IAAI,KAAK,CAAC;AACrD,WAAM,IAAI,KAAK;;AAGjB,UAAM,KAAK,KAAK;AAChB,WAAO,eAAe,MAAM,SAAS,EAAE,YAAY,OAAO,CAAC;AAC3D,YAAQ,OAAO,MAAM;;GAExB,CAAC;AAEF,UAAQ,IAAI,OAAO,KAAK;AAExB,OAAK,QAAQ;AACb,OAAK,IAAI,eAAe;AACtB,QAAK,IAAI,MAAM,KAAK,MAAM,CAAC;IAC3B;EAEF,MAAM,OAAO;AAEb,SAAO,eAAe,MAAM,UAAU;GACpC,UAAU;GACV,cAAc;GACd,MAAuB,OAAY;AACjC,WAAO,OAAO,KAAK,CAAC,KAAK,MAAM,MAAM;;GAExC,CAAC;;;;;;;;;;;;;;;CAgBJ,OAAO,OAA4B;EACjC,MAAM,EAAE,aAAc,SAAS,KAAK;AACpC,SAAO,YAAY;;;;;;AAkBvB,OAAO,eAAe,UAAU,WAAW,OAAO;CAChD,cAAc;CACd,MAAM;AACJ,SAAO,OAAO,KAAK;;CAErB,IAAI,OAAO;AACT,SAAO,eAAe,MAAM,OAAO,EAAE,OAAO,CAAC;;CAEhD,CAAC;;;;;;AAOF,UAAU,GAAG;CACX,OAAO,MAAM;AAGX,MAFY,OAAO,yBAAyB,MAAM,MAAM,EAE/C,aACP,QAAO,eAAe,MAAM,OAAO;GACjC,YAAY;GACZ,UAAU;GACX,CAAC;;CAEN,KAAK,MAAM;EACT,MAAM,OAAO,OAAO,yBAAyB,KAAK,WAAW,SAAS;AAEtE,MAAI,QAAQ,OAAO,KAAK,SAAS,WAC/B,QAAO,eAAe,KAAK,WAAW,UAAU;GAC9C,GAAG;GACH,cAAc;GACf,CAAC;;CAEP,CAAC;;;;;;;AAQF,SAAS,OAAO,QAAmB;CACjC,MAAM,SAAS,MAAM,IAAI,OAAO,YAAY;AAE5C,KAAI,OAAQ,QAAO;CAEnB,IAAI;CACJ,IAAI,QAAQ;AAEZ,SAAQ,QAAQ,OAAO,eAAe,MAAM,MAAM,UAAU,WAAW;EACrE,MAAM,OAAO,OAAO,yBAAyB,OAAO,SAAS;AAE7D,MAAI,MAAM;GACR,MAAM,QAAQ,OAAO,KAAK,OAAO,KAAK,MAAM;AAC5C,YAAS,SAAS,QAAQ,OAAO,OAAO,GAAG;;;AAI/C,KAAI,CAAC,OACH,UAAS,UAAU,UAAU;AAE/B,OAAM,IAAI,OAAO,aAAa,OAAO;AAErC,QAAO;;;AAIT,SAAS,QAAQ,OAAiB,OAA2B;AAC3D,QAAO,SAA2B,OAAY;EAC5C,MAAM,OAAO;AACb,SAAO,MAAM,KAAK,MAAM;GACtB,GAAG;GACH,IAAI,WAAW;AACb,WAAO,MAAM,KAAK,MAAM,MAAM;;GAEjC,CAAC;;;;AAKN,SAAS,UAAU;AACjB,yBAAQ,IAAI,SAAS"}
package/dist/context.js CHANGED
@@ -1,5 +1,5 @@
1
- import { event, listener } from "./observable.js";
2
1
  import { State, uid } from "./state.js";
2
+ import { event, listener } from "./observable.js";
3
3
 
4
4
  //#region src/context.ts
5
5
  const LOOKUP = /* @__PURE__ */ new WeakMap();
@@ -14,7 +14,7 @@ declare function hold(detached?: true, transition?: Transition): Hold | undefine
14
14
  * subscriber defers - it brackets the replay, but only where the scheduled
15
15
  * work asked for one.
16
16
  */
17
- declare function enqueue(handler: Handler, transition?: Transition): void;
17
+ declare function enqueue(handler: Handler, transition?: Transition, owner?: object): void;
18
18
  /**
19
19
  * Run `work` now, marking the subscriber updates it queues non-urgent - each
20
20
  * replays through whatever scheduler it subscribed with. The callback itself is
package/dist/dispatch.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { fault } from "./state.js";
2
+
1
3
  //#region src/dispatch.ts
2
4
  const DISPATCH = /* @__PURE__ */ new Map();
3
5
  let current;
@@ -57,7 +59,7 @@ function flush() {
57
59
  if (transition) transition(handler);
58
60
  else handler();
59
61
  } catch (err) {
60
- console.error(err);
62
+ fault(err, scheduled.owner);
61
63
  } finally {
62
64
  current = replaying = void 0;
63
65
  }
@@ -69,11 +71,14 @@ function flush() {
69
71
  * subscriber defers - it brackets the replay, but only where the scheduled
70
72
  * work asked for one.
71
73
  */
72
- function enqueue(handler, transition) {
74
+ function enqueue(handler, transition, owner) {
73
75
  if (!DISPATCH.size) queueMicrotask(flush);
74
76
  const scheduled = DISPATCH.get(handler);
75
77
  if (!scheduled) {
76
- const next = { transition: current ? transition : void 0 };
78
+ const next = {
79
+ transition: current ? transition : void 0,
80
+ owner
81
+ };
77
82
  DISPATCH.set(handler, next);
78
83
  claim(next);
79
84
  } else if (current) claim(scheduled);
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"dispatch.js","names":[],"sources":["../src/dispatch.ts"],"sourcesContent":["import { fault } from './state';\n\ntype 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 owner?: object;\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 fault(err, scheduled.owner);\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, owner?: object) {\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 owner\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":";;;AAoBA,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,SAAM,KAAK,UAAU,MAAM;YACnB;AACR,aAAU,YAAY;;AAGxB,MAAI,CAAC,UAAU,MAAO,MAAK,UAAU;;;;;;;;AASzC,SAAS,QAAQ,SAAkB,YAAyB,OAAgB;AAC1E,KAAI,CAAC,SAAS,KAAM,gBAAe,MAAM;CAEzC,MAAM,YAAY,SAAS,IAAI,QAAQ;AAEvC,KAAI,CAAC,WAAW;EACd,MAAM,OAAkB;GACtB,YAAY,UAAU,aAAa;GACnC;GACD;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/def.js CHANGED
@@ -1,5 +1,5 @@
1
- import { listener } from "../observable.js";
2
1
  import { PENDING, STORE, State, apply, uid } from "../state.js";
2
+ import { listener } from "../observable.js";
3
3
 
4
4
  //#region src/field/def.ts
5
5
  const APPLY = /* @__PURE__ */ new Map();
@@ -18,6 +18,7 @@ State.on((self) => {
18
18
  const entry = APPLY.get(property.value);
19
19
  if (entry === null) throw new Error(`${self}.${key} has an instruction applied to another State.`);
20
20
  if (!entry) continue;
21
+ if (key[0] == "_") throw new Error(`${self}.${key} is unmanaged - instructions cannot apply to _ keys.`);
21
22
  const [instruction, pending] = entry;
22
23
  APPLY.set(property.value, null);
23
24
  discard(self, pending);
@@ -1 +1 @@
1
- {"version":3,"file":"def.js","names":[],"sources":["../../src/field/def.ts"],"sourcesContent":["import { listener } from '../observable';\nimport { PENDING, State, STORE, uid, apply } from '../state';\n\ndeclare namespace def {\n /**\n * Property initializer, will run upon instance creation.\n * Optional returned callback will run when once upon first access.\n */\n type Factory<T = any, M extends State = any> = (\n this: M,\n key: Extract<State.Field<M>, string>,\n thisArg: M,\n state: State.Values<M>\n ) => def.Config<T> | (() => void) | void;\n\n interface Config<T = any> extends State.Apply<T> {\n destroy?: () => void;\n }\n}\n\nconst APPLY = new Map<symbol, [def.Factory, State[]] | null>();\nconst RESET = () => APPLY.clear();\n\nfunction def<T>(arg1: def.Factory<T>) {\n if (!PENDING.size || (PENDING.size == 1 && PENDING.has(RESET)))\n throw new Error(\n 'Instruction created with no State under construction.'\n );\n\n PENDING.add(RESET);\n\n const token = Symbol('field-' + uid());\n\n APPLY.set(token, [arg1, [...PENDING].filter((x) => x instanceof State) as State[]]);\n\n return token as T extends void ? unknown : T;\n}\n\nState.on((self) => {\n const store = STORE.get(self)!;\n\n for (const key in self) {\n const property: PropertyDescriptor = Object.getOwnPropertyDescriptor(self, key) || {};\n const entry = APPLY.get(property.value);\n\n if (entry === null)\n throw new Error(\n `${self}.${key} has an instruction applied to another State.`\n );\n\n if (!entry) continue;\n\n const [instruction, pending] = entry;\n\n APPLY.set(property.value, null);\n discard(self, pending);\n delete (self as any)[key];\n\n const output = instruction.call(self, key, self, store);\n\n if (!output) continue;\n\n const desc = typeof output == 'function' ? { destroy: output } : output;\n\n if (desc.destroy) listener(self, desc.destroy, null);\n\n apply(self, key, desc, true);\n }\n});\n\n/**\n * Drop pending States constructed after `self` and before the instruction -\n * products of its own initializers, discarded when this token replaced them.\n */\nfunction discard(self: State, pending: State[]) {\n let seen = false;\n\n for (const item of pending)\n if (!seen) seen = item === self;\n else PENDING.delete(item);\n}\n\nexport { def };\n"],"mappings":";;;;AAoBA,MAAM,wBAAQ,IAAI,KAA4C;AAC9D,MAAM,cAAc,MAAM,OAAO;AAEjC,SAAS,IAAO,MAAsB;AACpC,KAAI,CAAC,QAAQ,QAAS,QAAQ,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAC3D,OAAM,IAAI,MACR,wDACD;AAEH,SAAQ,IAAI,MAAM;CAElB,MAAM,QAAQ,OAAO,WAAW,KAAK,CAAC;AAEtC,OAAM,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,MAAM,aAAa,MAAM,CAAY,CAAC;AAEnF,QAAO;;AAGT,MAAM,IAAI,SAAS;CACjB,MAAM,QAAQ,MAAM,IAAI,KAAK;AAE7B,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,WAA+B,OAAO,yBAAyB,MAAM,IAAI,IAAI,EAAE;EACrF,MAAM,QAAQ,MAAM,IAAI,SAAS,MAAM;AAEvC,MAAI,UAAU,KACZ,OAAM,IAAI,MACR,GAAG,KAAK,GAAG,IAAI,+CAChB;AAEH,MAAI,CAAC,MAAO;EAEZ,MAAM,CAAC,aAAa,WAAW;AAE/B,QAAM,IAAI,SAAS,OAAO,KAAK;AAC/B,UAAQ,MAAM,QAAQ;AACtB,SAAQ,KAAa;EAErB,MAAM,SAAS,YAAY,KAAK,MAAM,KAAK,MAAM,MAAM;AAEvD,MAAI,CAAC,OAAQ;EAEb,MAAM,OAAO,OAAO,UAAU,aAAa,EAAE,SAAS,QAAQ,GAAG;AAEjE,MAAI,KAAK,QAAS,UAAS,MAAM,KAAK,SAAS,KAAK;AAEpD,QAAM,MAAM,KAAK,MAAM,KAAK;;EAE9B;;;;;AAMF,SAAS,QAAQ,MAAa,SAAkB;CAC9C,IAAI,OAAO;AAEX,MAAK,MAAM,QAAQ,QACjB,KAAI,CAAC,KAAM,QAAO,SAAS;KACtB,SAAQ,OAAO,KAAK"}
1
+ {"version":3,"file":"def.js","names":[],"sources":["../../src/field/def.ts"],"sourcesContent":["import { listener } from '../observable';\nimport { PENDING, State, STORE, uid, apply } from '../state';\n\ndeclare namespace def {\n /**\n * Property initializer, will run upon instance creation.\n * Optional returned callback will run when once upon first access.\n */\n type Factory<T = any, M extends State = any> = (\n this: M,\n key: Extract<State.Field<M>, string>,\n thisArg: M,\n state: State.Values<M>\n ) => def.Config<T> | (() => void) | void;\n\n interface Config<T = any> extends State.Apply<T> {\n destroy?: () => void;\n }\n}\n\nconst APPLY = new Map<symbol, [def.Factory, State[]] | null>();\nconst RESET = () => APPLY.clear();\n\nfunction def<T>(arg1: def.Factory<T>) {\n if (!PENDING.size || (PENDING.size == 1 && PENDING.has(RESET)))\n throw new Error(\n 'Instruction created with no State under construction.'\n );\n\n PENDING.add(RESET);\n\n const token = Symbol('field-' + uid());\n\n APPLY.set(token, [arg1, [...PENDING].filter((x) => x instanceof State) as State[]]);\n\n return token as T extends void ? unknown : T;\n}\n\nState.on((self) => {\n const store = STORE.get(self)!;\n\n for (const key in self) {\n const property: PropertyDescriptor = Object.getOwnPropertyDescriptor(self, key) || {};\n const entry = APPLY.get(property.value);\n\n if (entry === null)\n throw new Error(\n `${self}.${key} has an instruction applied to another State.`\n );\n\n if (!entry) continue;\n\n if (key[0] == '_')\n throw new Error(`${self}.${key} is unmanaged - instructions cannot apply to _ keys.`);\n\n const [instruction, pending] = entry;\n\n APPLY.set(property.value, null);\n discard(self, pending);\n delete (self as any)[key];\n\n const output = instruction.call(self, key, self, store);\n\n if (!output) continue;\n\n const desc = typeof output == 'function' ? { destroy: output } : output;\n\n if (desc.destroy) listener(self, desc.destroy, null);\n\n apply(self, key, desc, true);\n }\n});\n\n/**\n * Drop pending States constructed after `self` and before the instruction -\n * products of its own initializers, discarded when this token replaced them.\n */\nfunction discard(self: State, pending: State[]) {\n let seen = false;\n\n for (const item of pending)\n if (!seen) seen = item === self;\n else PENDING.delete(item);\n}\n\nexport { def };\n"],"mappings":";;;;AAoBA,MAAM,wBAAQ,IAAI,KAA4C;AAC9D,MAAM,cAAc,MAAM,OAAO;AAEjC,SAAS,IAAO,MAAsB;AACpC,KAAI,CAAC,QAAQ,QAAS,QAAQ,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAC3D,OAAM,IAAI,MACR,wDACD;AAEH,SAAQ,IAAI,MAAM;CAElB,MAAM,QAAQ,OAAO,WAAW,KAAK,CAAC;AAEtC,OAAM,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,MAAM,aAAa,MAAM,CAAY,CAAC;AAEnF,QAAO;;AAGT,MAAM,IAAI,SAAS;CACjB,MAAM,QAAQ,MAAM,IAAI,KAAK;AAE7B,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,WAA+B,OAAO,yBAAyB,MAAM,IAAI,IAAI,EAAE;EACrF,MAAM,QAAQ,MAAM,IAAI,SAAS,MAAM;AAEvC,MAAI,UAAU,KACZ,OAAM,IAAI,MACR,GAAG,KAAK,GAAG,IAAI,+CAChB;AAEH,MAAI,CAAC,MAAO;AAEZ,MAAI,IAAI,MAAM,IACZ,OAAM,IAAI,MAAM,GAAG,KAAK,GAAG,IAAI,sDAAsD;EAEvF,MAAM,CAAC,aAAa,WAAW;AAE/B,QAAM,IAAI,SAAS,OAAO,KAAK;AAC/B,UAAQ,MAAM,QAAQ;AACtB,SAAQ,KAAa;EAErB,MAAM,SAAS,YAAY,KAAK,MAAM,KAAK,MAAM,MAAM;AAEvD,MAAI,CAAC,OAAQ;EAEb,MAAM,OAAO,OAAO,UAAU,aAAa,EAAE,SAAS,QAAQ,GAAG;AAEjE,MAAI,KAAK,QAAS,UAAS,MAAM,KAAK,SAAS,KAAK;AAEpD,QAAM,MAAM,KAAK,MAAM,KAAK;;EAE9B;;;;;AAMF,SAAS,QAAQ,MAAa,SAAkB;CAC9C,IAAI,OAAO;AAEX,MAAK,MAAM,QAAQ,QACjB,KAAI,CAAC,KAAM,QAAO,SAAS;KACtB,SAAQ,OAAO,KAAK"}
package/dist/field/get.js CHANGED
@@ -1,5 +1,5 @@
1
- import { capture, listener, observer } from "../observable.js";
2
1
  import { STORE, children, parent, update } from "../state.js";
2
+ import { capture, listener, observer } from "../observable.js";
3
3
  import { Context } from "../context.js";
4
4
  import { def } from "./def.js";
5
5
 
@@ -4,11 +4,11 @@ import { State } from "../state.js";
4
4
  type Predicate<T> = (value: T, index: number, self: unknown) => boolean;
5
5
  type Mapper<T, U> = (value: T, index: number, self: unknown) => U;
6
6
  declare namespace has {
7
- export { Predicate, Mapper, List, Pool };
7
+ export { Predicate, Mapper, List, Pool, Create, From };
8
8
  }
9
9
  declare function has<T>(initial?: Iterable<T> | false | null): List<T>;
10
- declare function has<T extends State>(Type: new (...args: State.Args<T>) => T): Pool<T, State.Args<T> | [T]>;
11
- declare function has<T extends State, K extends State.Field<T>>(Type: new (...args: State.Args<T>) => T, fromKey: K): Pool<T, [T[K]] | [T]>;
10
+ declare function has<T extends State>(Type: new (...args: State.Args<T>) => T): Create<T>;
11
+ declare function has<T extends State, K extends State.Field<T>>(Type: new (...args: State.Args<T>) => T, fromKey: K): From<T, K>;
12
12
  declare function has<R, A extends unknown[]>(make: (...args: A) => R): Pool<Exclude<R, null | undefined>, A, R>;
13
13
  declare class List<T> {
14
14
  constructor(initial?: Iterable<T> | false | null);
@@ -31,6 +31,14 @@ declare class List<T> {
31
31
  any(fn: Predicate<T>): boolean;
32
32
  all(fn: Predicate<T>): boolean;
33
33
  }
34
+ interface Create<T extends State> extends Pool<T, State.Args<T>> {
35
+ add(...args: State.Args<T>): T;
36
+ add(instance: T): T;
37
+ }
38
+ interface From<T extends State, K extends State.Field<T>> extends Pool<T, [from: T[K]]> {
39
+ add(from: T[K]): T;
40
+ add(instance: T): T;
41
+ }
34
42
  declare class Pool<T, A extends unknown[] = unknown[], R = T> {
35
43
  constructor(make: Function, fromKey?: string);
36
44
  get size(): number;
package/dist/field/has.js CHANGED
@@ -1,5 +1,5 @@
1
- import { event, listener, touch } from "../observable.js";
2
1
  import { State, parent } from "../state.js";
2
+ import { event, listener, touch } from "../observable.js";
3
3
  import { Context } from "../context.js";
4
4
  import { def } from "./def.js";
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"has.js","names":[],"sources":["../../src/field/has.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport { State, parent } from '../state';\nimport { def } from './def';\n\nconst LENGTH = Symbol('length');\nconst SHAPE = Symbol('shape');\n\nconst ITEMS = new WeakMap<object, unknown[]>();\nconst MEMBERS = new WeakMap<object, Set<unknown>>();\nconst OWNED = new WeakMap<object, Map<unknown, () => void>>();\nconst MAKE = new WeakMap<object, Make>();\n\ntype Make = (...args: unknown[]) => unknown;\ntype Predicate<T> = (value: T, index: number, self: unknown) => boolean;\ntype Mapper<T, U> = (value: T, index: number, self: unknown) => U;\n\ndeclare namespace has {\n export { Predicate, Mapper, List, Pool }\n}\n\nfunction has<T>(initial?: Iterable<T> | false | null): List<T>;\n\nfunction has<T extends State>(\n Type: new (...args: State.Args<T>) => T\n): Pool<T, State.Args<T> | [T]>;\n\nfunction has<T extends State, K extends State.Field<T>>(\n Type: new (...args: State.Args<T>) => T,\n fromKey: K\n): Pool<T, [T[K]] | [T]>;\n\nfunction has<R, A extends unknown[]>(\n make: (...args: A) => R\n): Pool<Exclude<R, null | undefined>, A, R>;\n\nfunction has(\n arg?: Iterable<unknown> | Function | false | null,\n fromKey?: string\n): unknown {\n return def((_key, subject) => {\n const value =\n typeof arg == 'function' ? new Pool(arg, fromKey) : new List(arg);\n\n parent(value, subject);\n listener(subject, () => value.clear(), null);\n\n return { set: false, value };\n });\n}\n\nclass List<T> {\n constructor(initial?: Iterable<T> | false | null) {\n ITEMS.set(this, initial ? Array.from(initial) : []);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, LENGTH, items<T>(this).length);\n }\n\n get(): State.Export<T>[];\n get(index: number): T | undefined;\n get(start: number, end: number): T[];\n get(predicate: Predicate<T>): T | undefined;\n get(arg?: number | Predicate<T>, second?: number): any {\n const values = items<T>(this);\n\n if (arg === undefined) return values.map(exportValue);\n\n if (typeof arg === 'function') return findOf(this, arg);\n\n if (typeof second !== 'number') {\n const at = arg < 0 ? values.length + arg : arg;\n\n return at < 0 || at >= values.length\n ? touch(this, LENGTH)\n : touch(this, at, values[at]);\n }\n\n touch(this, LENGTH);\n\n const start = arg < 0 ? Math.max(values.length + arg, 0) : arg;\n\n return values\n .slice(start, Math.min(second, values.length))\n .map((v, i) => touch(this, start + i, v));\n }\n\n set(index: number, value: T) {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const at = index < 0 ? values.length + index : index;\n\n if (at < 0 || at >= values.length || values[at] === value) return;\n\n values[at] = value;\n event(target, at);\n }\n\n put(index: number, ...values: T[]) {\n if (!values.length) return;\n\n const target = source(this);\n const arr = ITEMS.get(target) as T[];\n const at =\n index < 0\n ? Math.max(arr.length + index, 0)\n : Math.min(index, arr.length);\n\n arr.splice(at, 0, ...values);\n\n for (let i = at; i < arr.length; i++) event(target, i);\n event(target, LENGTH);\n }\n\n push(...values: T[]): number {\n this.put(items(this).length, ...values);\n return items(this).length;\n }\n\n pop(): T | undefined;\n pop(index: number): T | undefined;\n pop(index: number, count: number): T[];\n pop(index = -1, count?: number): T | T[] | undefined {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const before = values.length;\n const start =\n index < 0 ? Math.max(before + index, 0) : Math.min(index, before);\n const removed = values.splice(start, count ?? 1);\n\n if (removed.length) {\n const end = Math.max(before, values.length);\n for (let i = start; i < end; i++) event(target, i);\n event(target, LENGTH);\n }\n\n return count === undefined ? removed[0] : removed;\n }\n\n clear() {\n this.pop(0, items(this).length);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = items<T>(this);\n\n touch(this, LENGTH);\n\n for (let i = 0; i < values.length; i++) yield touch(this, i, values[i]);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\nclass Pool<T, A extends unknown[] = unknown[], R = T> {\n constructor(make: Function, fromKey?: string) {\n if (State.is(make)) {\n const Type = make as unknown as State.Type;\n\n make = (...args: State.Args) =>\n args.length == 1 && args[0] instanceof Type ? args[0] :\n fromKey ? new Type({ [fromKey]: args[0] }) :\n new Type(...args);\n }\n\n MEMBERS.set(this, new Set());\n MAKE.set(this, make as Make);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, SHAPE, members<T>(this).size);\n }\n\n add(...args: A): R {\n const target = source(this);\n const made = MAKE.get(target)!(...args) as T | null | undefined;\n\n if (made == null) return made as R;\n\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(made)) {\n values.add(made);\n adopt(target, made, made);\n event(target, made as never);\n event(target, SHAPE);\n }\n\n return made as R;\n }\n\n get(): State.Export<T>[];\n get(predicate: Predicate<T>): T | undefined;\n get(predicate?: Predicate<T>): any {\n return predicate\n ? findOf(this, predicate)\n : Array.from(members<T>(this), exportValue);\n }\n\n has(value: T): boolean {\n return touch(this, value, members<T>(this).has(value));\n }\n\n delete(value: T): boolean {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(value)) return false;\n\n release(target, value);\n values.delete(value);\n\n event(target, value as never);\n event(target, SHAPE);\n\n return true;\n }\n\n clear() {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.size) return;\n\n const removed = Array.from(values);\n\n for (const value of removed) release(target, value);\n\n values.clear();\n\n for (const value of removed) event(target, value as never);\n event(target, SHAPE);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = members<T>(this);\n\n touch(this, SHAPE);\n\n for (const value of values) yield touch(this, value, value);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\nfunction source<T extends object>(from: T): T {\n return OWNED.has(from) ? from : Object.getPrototypeOf(from);\n}\n\nfunction adopt(\n target: { delete(key: never): boolean },\n key: unknown,\n value: unknown\n) {\n if (!(value instanceof State)) return;\n\n const owner = parent(target as object);\n const fresh = parent(value, owner ?? null);\n const evict = listener(value, () => void target.delete(key as never), null);\n\n let detach: (() => void) | undefined;\n\n if (fresh && owner)\n detach = Context.get(owner).add(value);\n\n OWNED.get(target)!.set(key, () => {\n evict();\n if (detach) detach();\n if (fresh) value.set(null);\n });\n\n if (fresh) event(value);\n}\n\nfunction release(target: object, key: unknown) {\n const owned = OWNED.get(target)!;\n const free = owned.get(key);\n\n if (free) {\n owned.delete(key);\n free();\n }\n}\n\nfunction exportValue(value: any) {\n return value && typeof value === 'object' && typeof value.get === 'function'\n ? value.get()\n : value;\n}\n\nfunction items<T>(from: object): T[] {\n return ITEMS.get(source(from)) as T[];\n}\n\nfunction members<T>(from: object): Set<T> {\n return MEMBERS.get(source(from)) as Set<T>;\n}\n\nfunction findOf<T>(\n self: Iterable<T>,\n fn: Predicate<T>\n): T | undefined {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return value;\n}\n\nfunction anyOf<T>(self: Iterable<T>, fn: Predicate<T>): boolean {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return true;\n\n return false;\n}\n\nfunction mapOf<T, U>(\n self: Iterable<T>,\n fn: Mapper<T, U>,\n skip: boolean,\n ignore?: U\n): U[] {\n const out: U[] = [];\n let i = 0;\n\n for (const value of self) {\n const result = fn(value, i++, self);\n if (skip && result === ignore) continue;\n out.push(result);\n }\n\n return out;\n}\n\nfunction filterOf<T>(self: Iterable<T>, fn: Predicate<T>): T[] {\n const out: T[] = [];\n let i = 0;\n\n for (const value of self) if (fn(value, i++, self)) out.push(value);\n\n return out;\n}\n\nObject.assign(has, { List, Pool });\n\nexport { has };\n"],"mappings":"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"}
1
+ {"version":3,"file":"has.js","names":[],"sources":["../../src/field/has.ts"],"sourcesContent":["import { Context } from '../context';\nimport { event, listener, touch } from '../observable';\nimport { State, parent } from '../state';\nimport { def } from './def';\n\nconst LENGTH = Symbol('length');\nconst SHAPE = Symbol('shape');\n\nconst ITEMS = new WeakMap<object, unknown[]>();\nconst MEMBERS = new WeakMap<object, Set<unknown>>();\nconst OWNED = new WeakMap<object, Map<unknown, () => void>>();\nconst MAKE = new WeakMap<object, Make>();\n\ntype Make = (...args: unknown[]) => unknown;\ntype Predicate<T> = (value: T, index: number, self: unknown) => boolean;\ntype Mapper<T, U> = (value: T, index: number, self: unknown) => U;\n\ndeclare namespace has {\n export { Predicate, Mapper, List, Pool, Create, From }\n}\n\nfunction has<T>(initial?: Iterable<T> | false | null): List<T>;\n\nfunction has<T extends State>(\n Type: new (...args: State.Args<T>) => T\n): Create<T>;\n\nfunction has<T extends State, K extends State.Field<T>>(\n Type: new (...args: State.Args<T>) => T,\n fromKey: K\n): From<T, K>;\n\nfunction has<R, A extends unknown[]>(\n make: (...args: A) => R\n): Pool<Exclude<R, null | undefined>, A, R>;\n\nfunction has(\n arg?: Iterable<unknown> | Function | false | null,\n fromKey?: string\n): unknown {\n return def((_key, subject) => {\n const value =\n typeof arg == 'function' ? new Pool(arg, fromKey) : new List(arg);\n\n parent(value, subject);\n listener(subject, () => value.clear(), null);\n\n return { set: false, value };\n });\n}\n\nclass List<T> {\n constructor(initial?: Iterable<T> | false | null) {\n ITEMS.set(this, initial ? Array.from(initial) : []);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, LENGTH, items<T>(this).length);\n }\n\n get(): State.Export<T>[];\n get(index: number): T | undefined;\n get(start: number, end: number): T[];\n get(predicate: Predicate<T>): T | undefined;\n get(arg?: number | Predicate<T>, second?: number): any {\n const values = items<T>(this);\n\n if (arg === undefined) return values.map(exportValue);\n\n if (typeof arg === 'function') return findOf(this, arg);\n\n if (typeof second !== 'number') {\n const at = arg < 0 ? values.length + arg : arg;\n\n return at < 0 || at >= values.length\n ? touch(this, LENGTH)\n : touch(this, at, values[at]);\n }\n\n touch(this, LENGTH);\n\n const start = arg < 0 ? Math.max(values.length + arg, 0) : arg;\n\n return values\n .slice(start, Math.min(second, values.length))\n .map((v, i) => touch(this, start + i, v));\n }\n\n set(index: number, value: T) {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const at = index < 0 ? values.length + index : index;\n\n if (at < 0 || at >= values.length || values[at] === value) return;\n\n values[at] = value;\n event(target, at);\n }\n\n put(index: number, ...values: T[]) {\n if (!values.length) return;\n\n const target = source(this);\n const arr = ITEMS.get(target) as T[];\n const at =\n index < 0\n ? Math.max(arr.length + index, 0)\n : Math.min(index, arr.length);\n\n arr.splice(at, 0, ...values);\n\n for (let i = at; i < arr.length; i++) event(target, i);\n event(target, LENGTH);\n }\n\n push(...values: T[]): number {\n this.put(items(this).length, ...values);\n return items(this).length;\n }\n\n pop(): T | undefined;\n pop(index: number): T | undefined;\n pop(index: number, count: number): T[];\n pop(index = -1, count?: number): T | T[] | undefined {\n const target = source(this);\n const values = ITEMS.get(target) as T[];\n const before = values.length;\n const start =\n index < 0 ? Math.max(before + index, 0) : Math.min(index, before);\n const removed = values.splice(start, count ?? 1);\n\n if (removed.length) {\n const end = Math.max(before, values.length);\n for (let i = start; i < end; i++) event(target, i);\n event(target, LENGTH);\n }\n\n return count === undefined ? removed[0] : removed;\n }\n\n clear() {\n this.pop(0, items(this).length);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = items<T>(this);\n\n touch(this, LENGTH);\n\n for (let i = 0; i < values.length; i++) yield touch(this, i, values[i]);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\ninterface Create<T extends State> extends Pool<T, State.Args<T>> {\n add(...args: State.Args<T>): T;\n add(instance: T): T;\n}\n\ninterface From<T extends State, K extends State.Field<T>>\n extends Pool<T, [from: T[K]]> {\n add(from: T[K]): T;\n add(instance: T): T;\n}\n\nclass Pool<T, A extends unknown[] = unknown[], R = T> {\n constructor(make: Function, fromKey?: string) {\n if (State.is(make)) {\n const Type = make as unknown as State.Type;\n\n make = (...args: State.Args) =>\n args.length == 1 && args[0] instanceof Type ? args[0] :\n fromKey ? new Type({ [fromKey]: args[0] }) :\n new Type(...args);\n }\n\n MEMBERS.set(this, new Set());\n MAKE.set(this, make as Make);\n OWNED.set(this, new Map());\n\n event(this);\n }\n\n get size(): number {\n return touch(this, SHAPE, members<T>(this).size);\n }\n\n add(...args: A): R {\n const target = source(this);\n const made = MAKE.get(target)!(...args) as T | null | undefined;\n\n if (made == null) return made as R;\n\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(made)) {\n values.add(made);\n adopt(target, made, made);\n event(target, made as never);\n event(target, SHAPE);\n }\n\n return made as R;\n }\n\n get(): State.Export<T>[];\n get(predicate: Predicate<T>): T | undefined;\n get(predicate?: Predicate<T>): any {\n return predicate\n ? findOf(this, predicate)\n : Array.from(members<T>(this), exportValue);\n }\n\n has(value: T): boolean {\n return touch(this, value, members<T>(this).has(value));\n }\n\n delete(value: T): boolean {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.has(value)) return false;\n\n release(target, value);\n values.delete(value);\n\n event(target, value as never);\n event(target, SHAPE);\n\n return true;\n }\n\n clear() {\n const target = source(this);\n const values = MEMBERS.get(target) as Set<T>;\n\n if (!values.size) return;\n\n const removed = Array.from(values);\n\n for (const value of removed) release(target, value);\n\n values.clear();\n\n for (const value of removed) event(target, value as never);\n event(target, SHAPE);\n }\n\n *[Symbol.iterator](): IterableIterator<T> {\n const values = members<T>(this);\n\n touch(this, SHAPE);\n\n for (const value of values) yield touch(this, value, value);\n }\n\n map<U>(fn: Mapper<T, U>): U[];\n map<U, X extends U>(fn: Mapper<T, U>, ignore: X): Exclude<U, X>[];\n map<U>(fn: Mapper<T, U>, ignore?: U): U[] {\n return mapOf(this, fn, arguments.length > 1, ignore);\n }\n\n filter(fn: Predicate<T>): T[] {\n return filterOf(this, fn);\n }\n\n any(fn: Predicate<T>): boolean {\n return anyOf(this, fn);\n }\n\n all(fn: Predicate<T>): boolean {\n return !anyOf(this, (v, i, self) => !fn(v, i, self));\n }\n}\n\nfunction source<T extends object>(from: T): T {\n return OWNED.has(from) ? from : Object.getPrototypeOf(from);\n}\n\nfunction adopt(\n target: { delete(key: never): boolean },\n key: unknown,\n value: unknown\n) {\n if (!(value instanceof State)) return;\n\n const owner = parent(target as object);\n const fresh = parent(value, owner ?? null);\n const evict = listener(value, () => void target.delete(key as never), null);\n\n let detach: (() => void) | undefined;\n\n if (fresh && owner)\n detach = Context.get(owner).add(value);\n\n OWNED.get(target)!.set(key, () => {\n evict();\n if (detach) detach();\n if (fresh) value.set(null);\n });\n\n if (fresh) event(value);\n}\n\nfunction release(target: object, key: unknown) {\n const owned = OWNED.get(target)!;\n const free = owned.get(key);\n\n if (free) {\n owned.delete(key);\n free();\n }\n}\n\nfunction exportValue(value: any) {\n return value && typeof value === 'object' && typeof value.get === 'function'\n ? value.get()\n : value;\n}\n\nfunction items<T>(from: object): T[] {\n return ITEMS.get(source(from)) as T[];\n}\n\nfunction members<T>(from: object): Set<T> {\n return MEMBERS.get(source(from)) as Set<T>;\n}\n\nfunction findOf<T>(\n self: Iterable<T>,\n fn: Predicate<T>\n): T | undefined {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return value;\n}\n\nfunction anyOf<T>(self: Iterable<T>, fn: Predicate<T>): boolean {\n let i = 0;\n\n for (const value of self)\n if (fn(value, i++, self)) return true;\n\n return false;\n}\n\nfunction mapOf<T, U>(\n self: Iterable<T>,\n fn: Mapper<T, U>,\n skip: boolean,\n ignore?: U\n): U[] {\n const out: U[] = [];\n let i = 0;\n\n for (const value of self) {\n const result = fn(value, i++, self);\n if (skip && result === ignore) continue;\n out.push(result);\n }\n\n return out;\n}\n\nfunction filterOf<T>(self: Iterable<T>, fn: Predicate<T>): T[] {\n const out: T[] = [];\n let i = 0;\n\n for (const value of self) if (fn(value, i++, self)) out.push(value);\n\n return out;\n}\n\nObject.assign(has, { List, Pool });\n\nexport { has };\n"],"mappings":"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"}
package/dist/field/map.js CHANGED
@@ -1,5 +1,5 @@
1
- import { event, listener, touch } from "../observable.js";
2
1
  import { State, parent } from "../state.js";
2
+ import { event, listener, touch } from "../observable.js";
3
3
  import { Context } from "../context.js";
4
4
  import { def } from "./def.js";
5
5
 
package/dist/field/ref.js CHANGED
@@ -1,5 +1,5 @@
1
- import { capture, listener } from "../observable.js";
2
1
  import { State, update } from "../state.js";
2
+ import { capture, listener } from "../observable.js";
3
3
  import { def } from "./def.js";
4
4
 
5
5
  //#region src/field/ref.ts
package/dist/field/set.js CHANGED
@@ -1,5 +1,5 @@
1
- import { capture, event, listener, observer } from "../observable.js";
2
1
  import { access, compute, update } from "../state.js";
2
+ import { capture, event, listener, observer } from "../observable.js";
3
3
  import { def } from "./def.js";
4
4
 
5
5
  //#region src/field/set.ts
package/dist/hot.d.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { State } from "./state.js";
2
+
3
+ //#region src/hot.d.ts
4
+ declare namespace hot_d_exports {
5
+ export { Replaced, accept, replaced };
6
+ }
7
+ interface Replaced {
8
+ /** Module id the class was accepted under. */
9
+ id: string;
10
+ /** Local declaration name of the class. */
11
+ name: string;
12
+ /** Class live instances belong to. */
13
+ prev: State.Extends;
14
+ /** Class that took its place. */
15
+ next: State.Extends;
16
+ }
17
+ /**
18
+ * Keep a module's State classes stable across runs. A class seen before is
19
+ * patched with its replacement and returned in its place, refreshing live
20
+ * instances; one whose shape or parent changed is returned as-is, and
21
+ * reported to `replaced` listeners before `accept` returns.
22
+ */
23
+ declare function accept<T extends Record<string, unknown>>(id: string, classes: T): T;
24
+ /**
25
+ * Observe classes `accept` replaced instead of patching. Fires synchronously
26
+ * inside `accept`, while the module re-runs, so a host can retire instances of
27
+ * `prev` before anything resolves the module again.
28
+ */
29
+ declare function replaced(listener: (event: Replaced) => void): () => void;
30
+ //#endregion
31
+ export { type Replaced, accept, hot_d_exports, replaced };
32
+ //# sourceMappingURL=hot.d.ts.map
package/dist/hot.js ADDED
@@ -0,0 +1,113 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { State, handlers, patch, track } from "./state.js";
3
+ import { event, observer } from "./observable.js";
4
+ import { rechain } from "./component.js";
5
+
6
+ //#region src/hot.ts
7
+ var hot_exports = /* @__PURE__ */ __exportAll({
8
+ accept: () => accept,
9
+ replaced: () => replaced
10
+ });
11
+ const MODULES = /* @__PURE__ */ new Map();
12
+ const LISTENERS = /* @__PURE__ */ new Set();
13
+ const REFRESH = Symbol.for("@expressive/mvc.refresh");
14
+ const PRIVATE = /(?:^|[\s;{}*])#[\w$]+(?=[\s=;(}])/;
15
+ function isState(value) {
16
+ return typeof value == "function" && value.prototype instanceof State;
17
+ }
18
+ /** What a patch cannot carry: class source less its members, and member kinds. */
19
+ function describe(type) {
20
+ const text = Function.prototype.toString;
21
+ const kinds = {};
22
+ let shape = text.call(type);
23
+ for (const target of [type.prototype, type]) for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(target))) for (const fn of [
24
+ desc.value,
25
+ desc.get,
26
+ desc.set
27
+ ]) if (typeof fn == "function" && fn !== type) {
28
+ shape = shape.replace(text.call(fn), "");
29
+ if (target !== type) kinds[key] = desc.set ? "accessor" : desc.get ? "get" : "fn";
30
+ }
31
+ return {
32
+ type,
33
+ shape: shape.replace(/\s+/g, " "),
34
+ kinds,
35
+ own: handlers(type)
36
+ };
37
+ }
38
+ function compatible(prev, next) {
39
+ if (prev.shape !== next.shape || PRIVATE.test(next.shape)) return false;
40
+ if (Object.getPrototypeOf(prev.type) !== Object.getPrototypeOf(next.type)) return false;
41
+ for (const key in next.kinds) if (key in prev.kinds && prev.kinds[key] !== next.kinds[key]) return false;
42
+ return true;
43
+ }
44
+ /**
45
+ * Keep a module's State classes stable across runs. A class seen before is
46
+ * patched with its replacement and returned in its place, refreshing live
47
+ * instances; one whose shape or parent changed is returned as-is, and
48
+ * reported to `replaced` listeners before `accept` returns.
49
+ */
50
+ function accept(id, classes) {
51
+ let known = MODULES.get(id);
52
+ if (!known) MODULES.set(id, known = {});
53
+ const output = { ...classes };
54
+ const refresh = /* @__PURE__ */ new Set();
55
+ const replace = [];
56
+ let patched = false;
57
+ track();
58
+ for (const [name, type] of Object.entries(classes)) {
59
+ if (!isState(type)) continue;
60
+ const prev = known[name];
61
+ if (prev?.type === type) continue;
62
+ const next = describe(type);
63
+ if (!prev || !compatible(prev, next)) {
64
+ if (prev) replace.push({
65
+ id,
66
+ name,
67
+ prev: prev.type,
68
+ next: type
69
+ });
70
+ known[name] = next;
71
+ continue;
72
+ }
73
+ try {
74
+ for (const state of patch(prev.type, type, prev.own)) refresh.add(state);
75
+ patched = true;
76
+ known[name] = {
77
+ ...next,
78
+ type: prev.type
79
+ };
80
+ output[name] = prev.type;
81
+ } catch (error) {
82
+ console.error(error);
83
+ replace.push({
84
+ id,
85
+ name,
86
+ prev: prev.type,
87
+ next: type
88
+ });
89
+ known[name] = next;
90
+ }
91
+ }
92
+ if (patched) rechain();
93
+ for (const state of refresh) if (observer(state)?.ready) event(state, REFRESH);
94
+ for (const event of replace) for (const listener of LISTENERS) try {
95
+ listener(event);
96
+ } catch (error) {
97
+ console.error(error);
98
+ }
99
+ return output;
100
+ }
101
+ /**
102
+ * Observe classes `accept` replaced instead of patching. Fires synchronously
103
+ * inside `accept`, while the module re-runs, so a host can retire instances of
104
+ * `prev` before anything resolves the module again.
105
+ */
106
+ function replaced(listener) {
107
+ LISTENERS.add(listener);
108
+ return () => void LISTENERS.delete(listener);
109
+ }
110
+
111
+ //#endregion
112
+ export { accept, hot_exports, replaced };
113
+ //# sourceMappingURL=hot.js.map