@expressive/mvc 0.87.0 → 0.88.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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 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"}
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({\n setup(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/**\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,GAAG,EACP,MAAM,MAAM;CACV,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;;GAGjC,CAAC;;;;;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 { STORE, children, parent, update } from "../state.js";
2
1
  import { capture, listener, observer } from "../observable.js";
2
+ import { STORE, State, children, owned, parent, update } from "../state.js";
3
3
  import { Context } from "../context.js";
4
4
  import { def } from "./def.js";
5
5
 
@@ -23,11 +23,26 @@ function above(Type, argument) {
23
23
  assign(hasParent);
24
24
  return {};
25
25
  }
26
+ if (Type === State) {
27
+ if (argument === false) return {
28
+ get: false,
29
+ enumerable: false
30
+ };
31
+ throw new Error(`${subject} has no owner.`);
32
+ }
26
33
  let found = false;
27
34
  let depth = Infinity;
28
35
  let level = 0;
29
36
  for (let p = hasParent; p; p = parent(p), level++) {
30
37
  const at = level;
38
+ if (p instanceof Type) {
39
+ if (!found) {
40
+ found = true;
41
+ depth = at;
42
+ assign(p);
43
+ }
44
+ break;
45
+ }
31
46
  const remove = children(p, (child) => {
32
47
  if (child !== subject && child instanceof Type && at <= depth) {
33
48
  found = true;
@@ -68,13 +83,14 @@ function above(Type, argument) {
68
83
  function below(Type, arg) {
69
84
  return def((key, subject) => {
70
85
  const context = Context.get(subject);
86
+ const watch = (callback) => Type === State ? owned(subject, callback) : context.get(Type, callback, true);
71
87
  if (typeof arg == "boolean") {
72
- context.get(Type, (state) => {
88
+ watch((state) => {
73
89
  update(subject, key, state);
74
90
  return state.set(null, () => {
75
91
  update(subject, key, void 0);
76
92
  });
77
- }, true);
93
+ });
78
94
  return {
79
95
  get: arg,
80
96
  value: void 0,
@@ -82,7 +98,7 @@ function below(Type, arg) {
82
98
  };
83
99
  }
84
100
  const applied = /* @__PURE__ */ new Set();
85
- context.get(Type, (state) => {
101
+ watch((state) => {
86
102
  let remove;
87
103
  let release;
88
104
  if (applied.has(state)) return;
@@ -107,7 +123,7 @@ function below(Type, arg) {
107
123
  }
108
124
  const ignore = state.set(null, done);
109
125
  return done;
110
- }, true);
126
+ });
111
127
  return {
112
128
  value: [],
113
129
  enumerable: false
@@ -1 +1 @@
1
- {"version":3,"file":"get.js","names":[],"sources":["../../src/field/get.ts"],"sourcesContent":["import { capture, listener, observer } from '../observable';\nimport { Context } from '../context';\nimport { State, children, parent, STORE, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace get {\n type Callback<T = any> = (\n state: T,\n subject: State\n ) => void | boolean | (() => void);\n}\n\n/**\n * Fetches upstream State from context with optional lifecycle callback.\n * Callback runs on mount and can return cleanup function for unmount.\n *\n * @param Type - Type of State to fetch.\n * @param callback - Optional lifecycle callback, receives (state, subject). Can return cleanup function.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n callback?: get.Callback<T>\n): T;\n\n/**\n * Fetches and assigns the controller which spawned this host.\n * When parent assigns an instance via `use()` directive, it\n * will be made available to child upon this request.\n *\n * @param Type - Type of controller compatible with this class.\n * @param required - If false, property may be undefined. Otherwise will throw.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n required: false\n): T | undefined;\n\n/**\n * Collects downstream States, accumulating all instances of specified type\n * for which this is an ancestor. Returns an array that updates as States\n * are added or removed. Callback runs on each registration and can return\n * cleanup or false to prevent registration.\n *\n * @param Type - Type of State to collect.\n * @param downstream - Must be true to enable downstream mode.\n * @param callback - Optional lifecycle callback, receives (state, subject). May return false to prevent registration.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n callback?: get.Callback<T>\n): T[];\n\n/**\n * Fetches a single downstream State of specified type.\n * Updates when a matching child appears or is removed.\n * Throws if not found.\n *\n * @param Type - Type of State to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - Throw if no match found.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n single: true\n): T;\n\n/**\n * Fetches a single downstream State of specified type.\n * Updates when a matching child appears or is removed.\n * Returns undefined if not found.\n *\n * @param Type - Type of State to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - If false, returns undefined if no match found.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n required: false\n): T | undefined;\n\nfunction get<T extends State>(\n Type: State.Extends<T>,\n arg1?: get.Callback<T> | boolean,\n arg2?: get.Callback<T> | boolean\n) {\n return arg1 === true ? below(Type, arg2) : above(Type, arg1);\n}\n\nfunction above<T extends State>(\n Type: State.Extends<T>,\n argument: get.Callback<T> | boolean | undefined\n) {\n return def<T>((key, subject) => {\n const hasParent = parent(subject);\n const callback =\n typeof argument === 'function'\n ? (argument as get.Callback<T>)\n : undefined;\n\n function assign(value: T) {\n if (STORE.get(subject)![key] === value) return;\n\n if (callback) {\n const result = callback(value, subject);\n if (typeof result === 'function') subject.set(null, result);\n }\n update(subject, key, value);\n }\n\n if (hasParent && hasParent instanceof Type) {\n assign(hasParent as T);\n return {};\n }\n\n let found = false;\n let depth = Infinity;\n let level = 0;\n\n for (let p: State | null | undefined = hasParent; p; p = parent(p), level++) {\n const at = level;\n\n const remove = children(p, (child) => {\n if (child !== subject && child instanceof Type && at <= depth) {\n found = true;\n depth = at;\n assign(child as T);\n }\n });\n\n subject.set(null, () => { remove(); });\n }\n\n if (!found) {\n const remove = Context.get(subject).get(Type, (state) => {\n if (depth !== Infinity) return;\n found = true;\n assign(state);\n }, false, subject) as () => void;\n\n subject.set(null, () => { remove(); });\n }\n\n if (!found && argument !== false) {\n const missing = () =>\n new Error(`Required ${Type} not found in context for ${subject}.`);\n\n let activating: State | undefined;\n\n for (\n let p: State | null | undefined = hasParent;\n p && !observer(p)!.ready;\n p = parent(p)\n )\n activating = p;\n\n if (!activating) throw missing();\n\n listener(activating, () => {\n if (!found) throw missing();\n return null;\n }, true);\n }\n\n return {\n get: argument !== false,\n enumerable: false\n };\n });\n}\n\nfunction below<T extends State>(\n Type: State.Extends<T>,\n arg: get.Callback<T> | boolean | undefined\n) {\n return def<T[]>((key, subject) => {\n const context = Context.get(subject);\n\n if (typeof arg == 'boolean') {\n context.get(\n Type,\n (state) => {\n update(subject, key, state);\n return state.set(null, () => {\n update(subject, key, undefined);\n });\n },\n true\n );\n\n return {\n get: arg,\n value: undefined,\n enumerable: false\n };\n }\n\n const applied = new Set<State>();\n\n context.get(\n Type,\n (state) => {\n let remove: (() => void) | undefined;\n let release: (() => void) | undefined;\n\n if (applied.has(state)) return;\n\n if (arg) {\n let rejected = false;\n\n capture((fn) => {\n const done = arg(state, subject);\n\n if (done === false) rejected = true;\n else if (typeof done == 'function') remove = done;\n\n release = fn;\n });\n\n if (rejected) return;\n }\n\n applied.add(state);\n update(subject, key, [...applied]);\n\n function done() {\n if (release) release();\n ignore();\n\n applied.delete(state);\n update(subject, key, [...applied]);\n\n if (typeof remove == 'function') remove();\n }\n\n const ignore = state.set(null, done);\n\n return done;\n },\n true\n );\n\n return {\n value: [],\n enumerable: false\n };\n });\n}\n\nexport { get };\n"],"mappings":"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"}
1
+ {"version":3,"file":"get.js","names":[],"sources":["../../src/field/get.ts"],"sourcesContent":["import { capture, listener, observer } from '../observable';\nimport { Context } from '../context';\nimport { State, children, owned, parent, STORE, update } from '../state';\nimport { def } from './def';\n\ndeclare namespace get {\n type Callback<T = any> = (\n state: T,\n subject: State\n ) => void | boolean | (() => void);\n}\n\n/**\n * Fetches upstream State from context with optional lifecycle callback.\n * Callback runs on mount and can return cleanup function for unmount.\n *\n * @param Type - Type of State to fetch.\n * @param callback - Optional lifecycle callback, receives (state, subject). Can return cleanup function.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n callback?: get.Callback<T>\n): T;\n\n/**\n * Fetches and assigns the controller which spawned this host.\n * When parent assigns an instance via `use()` directive, it\n * will be made available to child upon this request.\n *\n * @param Type - Type of controller compatible with this class.\n * @param required - If false, property may be undefined. Otherwise will throw.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n required: false\n): T | undefined;\n\n/**\n * Collects downstream States, accumulating all instances of specified type\n * for which this is an ancestor. Returns an array that updates as States\n * are added or removed. Callback runs on each registration and can return\n * cleanup or false to prevent registration.\n *\n * @param Type - Type of State to collect.\n * @param downstream - Must be true to enable downstream mode.\n * @param callback - Optional lifecycle callback, receives (state, subject). May return false to prevent registration.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n callback?: get.Callback<T>\n): T[];\n\n/**\n * Fetches a single downstream State of specified type.\n * Updates when a matching child appears or is removed.\n * Throws if not found.\n *\n * @param Type - Type of State to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - Throw if no match found.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n single: true\n): T;\n\n/**\n * Fetches a single downstream State of specified type.\n * Updates when a matching child appears or is removed.\n * Returns undefined if not found.\n *\n * @param Type - Type of State to fetch.\n * @param downstream - Must be true to enable downstream mode.\n * @param required - If false, returns undefined if no match found.\n */\nfunction get<T extends State>(\n Type: State.Extends<T>,\n downstream: true,\n required: false\n): T | undefined;\n\nfunction get<T extends State>(\n Type: State.Extends<T>,\n arg1?: get.Callback<T> | boolean,\n arg2?: get.Callback<T> | boolean\n) {\n return arg1 === true ? below(Type, arg2) : above(Type, arg1);\n}\n\nfunction above<T extends State>(\n Type: State.Extends<T>,\n argument: get.Callback<T> | boolean | undefined\n) {\n return def<T>((key, subject) => {\n const hasParent = parent(subject);\n const callback =\n typeof argument === 'function'\n ? (argument as get.Callback<T>)\n : undefined;\n\n function assign(value: T) {\n if (STORE.get(subject)![key] === value) return;\n\n if (callback) {\n const result = callback(value, subject);\n if (typeof result === 'function') subject.set(null, result);\n }\n update(subject, key, value);\n }\n\n if (hasParent && hasParent instanceof Type) {\n assign(hasParent as T);\n return {};\n }\n\n if (Type === State) {\n if (argument === false) return { get: false, enumerable: false };\n throw new Error(`${subject} has no owner.`);\n }\n\n let found = false;\n let depth = Infinity;\n let level = 0;\n\n for (let p: State | null | undefined = hasParent; p; p = parent(p), level++) {\n const at = level;\n\n if (p instanceof Type) {\n if (!found) {\n found = true;\n depth = at;\n assign(p as T);\n }\n break;\n }\n\n const remove = children(p, (child) => {\n if (child !== subject && child instanceof Type && at <= depth) {\n found = true;\n depth = at;\n assign(child as T);\n }\n });\n\n subject.set(null, () => { remove(); });\n }\n\n if (!found) {\n const remove = Context.get(subject).get(Type, (state) => {\n if (depth !== Infinity) return;\n found = true;\n assign(state);\n }, false, subject) as () => void;\n\n subject.set(null, () => { remove(); });\n }\n\n if (!found && argument !== false) {\n const missing = () =>\n new Error(`Required ${Type} not found in context for ${subject}.`);\n\n let activating: State | undefined;\n\n for (\n let p: State | null | undefined = hasParent;\n p && !observer(p)!.ready;\n p = parent(p)\n )\n activating = p;\n\n if (!activating) throw missing();\n\n listener(activating, () => {\n if (!found) throw missing();\n return null;\n }, true);\n }\n\n return {\n get: argument !== false,\n enumerable: false\n };\n });\n}\n\nfunction below<T extends State>(\n Type: State.Extends<T>,\n arg: get.Callback<T> | boolean | undefined\n) {\n return def<T[]>((key, subject) => {\n const context = Context.get(subject);\n const watch = (callback: (state: T) => (() => void) | void) =>\n Type === State\n ? owned(subject, callback as (state: State) => (() => void) | void)\n : context.get(Type, callback, true);\n\n if (typeof arg == 'boolean') {\n watch(\n (state) => {\n update(subject, key, state);\n return state.set(null, () => {\n update(subject, key, undefined);\n });\n }\n );\n\n return {\n get: arg,\n value: undefined,\n enumerable: false\n };\n }\n\n const applied = new Set<State>();\n\n watch(\n (state) => {\n let remove: (() => void) | undefined;\n let release: (() => void) | undefined;\n\n if (applied.has(state)) return;\n\n if (arg) {\n let rejected = false;\n\n capture((fn) => {\n const done = arg(state, subject);\n\n if (done === false) rejected = true;\n else if (typeof done == 'function') remove = done;\n\n release = fn;\n });\n\n if (rejected) return;\n }\n\n applied.add(state);\n update(subject, key, [...applied]);\n\n function done() {\n if (release) release();\n ignore();\n\n applied.delete(state);\n update(subject, key, [...applied]);\n\n if (typeof remove == 'function') remove();\n }\n\n const ignore = state.set(null, done);\n\n return done;\n }\n );\n\n return {\n value: [],\n enumerable: false\n };\n });\n}\n\nexport { get };\n"],"mappings":"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"}
package/dist/field/has.js CHANGED
@@ -1,5 +1,5 @@
1
- import { State, parent } from "../state.js";
2
1
  import { event, listener, touch } from "../observable.js";
2
+ import { State, parent } from "../state.js";
3
3
  import { Context } from "../context.js";
4
4
  import { def } from "./def.js";
5
5
 
package/dist/field/map.js CHANGED
@@ -1,5 +1,5 @@
1
- import { State, parent } from "../state.js";
2
1
  import { event, listener, touch } from "../observable.js";
2
+ import { State, parent } from "../state.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 { State, update } from "../state.js";
2
1
  import { capture, listener } from "../observable.js";
2
+ import { State, update } from "../state.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 { access, compute, update } from "../state.js";
2
1
  import { capture, event, listener, observer } from "../observable.js";
2
+ import { access, compute, update } from "../state.js";
3
3
  import { def } from "./def.js";
4
4
 
5
5
  //#region src/field/set.ts
package/dist/hot.d.ts CHANGED
@@ -1,9 +1,6 @@
1
1
  import { State } from "./state.js";
2
2
 
3
3
  //#region src/hot.d.ts
4
- declare namespace hot_d_exports {
5
- export { Replaced, accept, replaced };
6
- }
7
4
  interface Replaced {
8
5
  /** Module id the class was accepted under. */
9
6
  id: string;
@@ -28,5 +25,5 @@ declare function accept<T extends Record<string, unknown>>(id: string, classes:
28
25
  */
29
26
  declare function replaced(listener: (event: Replaced) => void): () => void;
30
27
  //#endregion
31
- export { type Replaced, accept, hot_d_exports, replaced };
28
+ export { type Replaced, accept, replaced };
32
29
  //# sourceMappingURL=hot.d.ts.map
package/dist/hot.js CHANGED
@@ -1,17 +1,128 @@
1
- import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
- import { State, handlers, patch, track } from "./state.js";
3
- import { event, observer } from "./observable.js";
1
+ import { event } from "./observable.js";
2
+ import { GETTERS, LATEST, METHODS, SETUP, State, UNBIND, classify, compute } from "./state.js";
4
3
  import { rechain } from "./component.js";
5
4
 
6
5
  //#region src/hot.ts
7
- var hot_exports = /* @__PURE__ */ __exportAll({
8
- accept: () => accept,
9
- replaced: () => replaced
10
- });
6
+ const define = Object.defineProperty;
7
+ /** Method implementations replaced by a hot patch. */
8
+ const PAST = /* @__PURE__ */ new WeakSet();
9
+ /** Live instances, tracked once hot patching is enabled. */
10
+ let LIVE;
11
+ /** Bootstrapped subclasses of each class, tracked once hot patching is enabled. */
12
+ const SUBCLASSES = /* @__PURE__ */ new WeakMap();
11
13
  const MODULES = /* @__PURE__ */ new Map();
12
14
  const LISTENERS = /* @__PURE__ */ new Set();
13
15
  const REFRESH = Symbol.for("@expressive/mvc.refresh");
14
16
  const PRIVATE = /(?:^|[\s;{}*])#[\w$]+(?=[\s=;(}])/;
17
+ /** Begin tracking live instances, so a hot patch can reach them. */
18
+ function track() {
19
+ if (LIVE) return;
20
+ LIVE = /* @__PURE__ */ new Set();
21
+ State.on({
22
+ type(type) {
23
+ const parent = Object.getPrototypeOf(type);
24
+ let children = SUBCLASSES.get(parent);
25
+ if (!children) SUBCLASSES.set(parent, children = /* @__PURE__ */ new Set());
26
+ children.add(type);
27
+ },
28
+ setup(state) {
29
+ const ref = new WeakRef(state);
30
+ LIVE.add(ref);
31
+ return () => LIVE.delete(ref);
32
+ }
33
+ });
34
+ }
35
+ /**
36
+ * Move the members of `next` onto `prev`, which keeps its identity. Returns the
37
+ * live instances of `prev`, each needing a refresh.
38
+ */
39
+ function patch(prev, next, own) {
40
+ const proto = prev.prototype;
41
+ const incoming = Object.getOwnPropertyDescriptors(next.prototype);
42
+ const keys = METHODS.get(prev);
43
+ const getters = GETTERS.get(prev);
44
+ const methods = /* @__PURE__ */ new Map();
45
+ const knownKeys = new Set(keys?.keys());
46
+ const knownGetters = new Set(getters?.keys());
47
+ let setup = SETUP.get(prev);
48
+ for (const handler of own) setup.delete(handler);
49
+ for (const handler of handlers(next)) {
50
+ if (!setup) SETUP.set(prev, setup = /* @__PURE__ */ new Set());
51
+ setup.add(handler);
52
+ }
53
+ for (const key of Reflect.ownKeys(next)) {
54
+ if (key == "prototype" || key == "length" || key == "name") continue;
55
+ if (Object.getOwnPropertyDescriptor(prev, key)?.configurable !== false) define(prev, key, Object.getOwnPropertyDescriptor(next, key));
56
+ }
57
+ const removed = /* @__PURE__ */ new Set();
58
+ for (const key of Object.getOwnPropertyNames(proto)) if (key != "constructor" && !(key in incoming)) {
59
+ const bind = keys?.get(key);
60
+ if (bind && Object.getOwnPropertyDescriptor(proto, key).get === bind) {
61
+ PAST.add(UNBIND.get(bind));
62
+ keys.delete(key);
63
+ }
64
+ removed.add(key);
65
+ Reflect.deleteProperty(proto, key);
66
+ getters?.delete(key);
67
+ }
68
+ for (const [key, desc] of Object.entries(incoming)) {
69
+ if (key == "constructor") continue;
70
+ const current = Object.getOwnPropertyDescriptor(proto, key);
71
+ if (typeof desc.value == "function") methods.set(key, desc.value);
72
+ if (current?.configurable === false) {
73
+ if (current.writable) proto[key] = desc.value;
74
+ continue;
75
+ }
76
+ if (current?.get && keys?.get(key) === current.get) PAST.add(UNBIND.get(current.get));
77
+ const getter = getters?.get(key);
78
+ if (getter) LATEST.set(getter, desc.get);
79
+ define(proto, key, {
80
+ ...desc,
81
+ configurable: true
82
+ });
83
+ }
84
+ if (keys) {
85
+ for (let T = prev;; T = Object.getPrototypeOf(T)) {
86
+ for (const handler of SETUP.get(T) || []) if (handler.type) handler.type(prev);
87
+ if (T === State) break;
88
+ }
89
+ classify(prev, keys, getters);
90
+ }
91
+ const live = [];
92
+ for (const ref of LIVE) {
93
+ const state = ref.deref();
94
+ if (!state) LIVE.delete(ref);
95
+ else if (state instanceof prev) live.push(state);
96
+ }
97
+ const descendants = new Set([prev, ...live.map((state) => state.constructor)]);
98
+ for (const type of descendants) for (const child of SUBCLASSES.get(type) || []) descendants.add(child);
99
+ descendants.delete(prev);
100
+ for (const type of descendants) {
101
+ const inherit = METHODS.get(type);
102
+ const computed = GETTERS.get(type);
103
+ for (const [key, bind] of keys) if (!knownKeys.has(key) && !inherit.has(key)) inherit.set(key, bind);
104
+ for (const [key, get] of getters) if (!knownGetters.has(key) && !computed.has(key)) computed.set(key, get);
105
+ for (const key of removed) if (!(key in type.prototype)) {
106
+ inherit.delete(key);
107
+ computed.delete(key);
108
+ }
109
+ }
110
+ for (const state of live) {
111
+ for (const [key, value] of methods) {
112
+ const desc = Object.getOwnPropertyDescriptor(state, key);
113
+ if (!desc) continue;
114
+ if (desc.set) desc.set.call(state, value);
115
+ else if (PAST.has(UNBIND.get(desc.value))) delete state[key];
116
+ }
117
+ for (const key of removed) if (PAST.has(UNBIND.get(Object.getOwnPropertyDescriptor(state, key)?.value))) delete state[key];
118
+ for (const [key, get] of GETTERS.get(state.constructor)) if (!knownGetters.has(key) && get === getters.get(key)) compute.call(state, get, key);
119
+ }
120
+ return live;
121
+ }
122
+ /** Lifecycle handlers registered on a class itself. */
123
+ function handlers(type) {
124
+ return [...SETUP.get(type) || []];
125
+ }
15
126
  function isState(value) {
16
127
  return typeof value == "function" && value.prototype instanceof State;
17
128
  }
@@ -28,9 +139,10 @@ function describe(type) {
28
139
  shape = shape.replace(text.call(fn), "");
29
140
  if (target !== type) kinds[key] = desc.set ? "accessor" : desc.get ? "get" : "fn";
30
141
  }
142
+ shape = shape.replace(/\s+/g, " ").replace(/__vite_ssr_import_\d+__/g, "__vite_ssr_import__");
31
143
  return {
32
144
  type,
33
- shape: shape.replace(/\s+/g, " "),
145
+ shape,
34
146
  kinds,
35
147
  own: handlers(type)
36
148
  };
@@ -90,7 +202,7 @@ function accept(id, classes) {
90
202
  }
91
203
  }
92
204
  if (patched) rechain();
93
- for (const state of refresh) if (observer(state)?.ready) event(state, REFRESH);
205
+ for (const state of refresh) event(state, REFRESH);
94
206
  for (const event of replace) for (const listener of LISTENERS) try {
95
207
  listener(event);
96
208
  } catch (error) {
@@ -109,5 +221,5 @@ function replaced(listener) {
109
221
  }
110
222
 
111
223
  //#endregion
112
- export { accept, hot_exports, replaced };
224
+ export { accept, replaced };
113
225
  //# sourceMappingURL=hot.js.map
package/dist/hot.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hot.js","names":[],"sources":["../src/hot.ts"],"sourcesContent":["import { rechain } from './component';\nimport { event, observer } from './observable';\nimport { State, handlers, patch, track } from './state';\n\ninterface Entry {\n type: Function;\n shape: string;\n kinds: Record<string, 'get' | 'accessor' | 'fn'>;\n own: ReturnType<typeof handlers>;\n}\n\ninterface Replaced {\n /** Module id the class was accepted under. */\n id: string;\n /** Local declaration name of the class. */\n name: string;\n /** Class live instances belong to. */\n prev: State.Extends;\n /** Class that took its place. */\n next: State.Extends;\n}\n\nconst MODULES = new Map<string, Record<string, Entry>>();\nconst LISTENERS = new Set<(event: Replaced) => void>();\nconst REFRESH = Symbol.for('@expressive/mvc.refresh');\nconst PRIVATE = /(?:^|[\\s;{}*])#[\\w$]+(?=[\\s=;(}])/;\n\nfunction isState(value: unknown): value is State.Extends {\n return typeof value == 'function' && value.prototype instanceof State;\n}\n\n/** What a patch cannot carry: class source less its members, and member kinds. */\nfunction describe(type: Function): Entry {\n const text = Function.prototype.toString;\n const kinds: Entry['kinds'] = {};\n let shape = text.call(type);\n\n for (const target of [type.prototype, type])\n for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(target)))\n for (const fn of [desc.value, desc.get, desc.set])\n if (typeof fn == 'function' && fn !== type) {\n shape = shape.replace(text.call(fn), '');\n if (target !== type) kinds[key] = desc.set ? 'accessor' : desc.get ? 'get' : 'fn';\n }\n\n return { type, shape: shape.replace(/\\s+/g, ' '), kinds, own: handlers(type as State.Extends) };\n}\n\nfunction compatible(prev: Entry, next: Entry) {\n if (prev.shape !== next.shape || PRIVATE.test(next.shape)) return false;\n if (Object.getPrototypeOf(prev.type) !== Object.getPrototypeOf(next.type)) return false;\n\n for (const key in next.kinds)\n if (key in prev.kinds && prev.kinds[key] !== next.kinds[key]) return false;\n\n return true;\n}\n\n/**\n * Keep a module's State classes stable across runs. A class seen before is\n * patched with its replacement and returned in its place, refreshing live\n * instances; one whose shape or parent changed is returned as-is, and\n * reported to `replaced` listeners before `accept` returns.\n */\nfunction accept<T extends Record<string, unknown>>(id: string, classes: T): T {\n let known = MODULES.get(id);\n\n if (!known) MODULES.set(id, (known = {}));\n\n const output: Record<string, unknown> = { ...classes };\n const refresh = new Set<State>();\n const replace: Replaced[] = [];\n let patched = false;\n\n track();\n\n for (const [name, type] of Object.entries(classes)) {\n if (!isState(type)) continue;\n\n const prev = known[name];\n\n if (prev?.type === type) continue;\n\n const next = describe(type);\n\n if (!prev || !compatible(prev, next)) {\n if (prev) replace.push({ id, name, prev: prev.type as State.Extends, next: type });\n known[name] = next;\n continue;\n }\n\n try {\n for (const state of patch(prev.type as State.Extends, type, prev.own)) refresh.add(state);\n patched = true;\n known[name] = { ...next, type: prev.type };\n output[name] = prev.type;\n } catch (error) {\n console.error(error);\n replace.push({ id, name, prev: prev.type as State.Extends, next: type });\n known[name] = next;\n }\n }\n\n if (patched) rechain();\n\n for (const state of refresh) if (observer(state)?.ready) event(state, REFRESH);\n\n for (const event of replace)\n for (const listener of LISTENERS)\n try {\n listener(event);\n } catch (error) {\n console.error(error);\n }\n\n return output as T;\n}\n\n/**\n * Observe classes `accept` replaced instead of patching. Fires synchronously\n * inside `accept`, while the module re-runs, so a host can retire instances of\n * `prev` before anything resolves the module again.\n */\nfunction replaced(listener: (event: Replaced) => void): () => void {\n LISTENERS.add(listener);\n return () => void LISTENERS.delete(listener);\n}\n\nexport { accept, replaced };\nexport type { Replaced };\n"],"mappings":";;;;;;;;;;AAsBA,MAAM,0BAAU,IAAI,KAAoC;AACxD,MAAM,4BAAY,IAAI,KAAgC;AACtD,MAAM,UAAU,OAAO,IAAI,0BAA0B;AACrD,MAAM,UAAU;AAEhB,SAAS,QAAQ,OAAwC;AACvD,QAAO,OAAO,SAAS,cAAc,MAAM,qBAAqB;;;AAIlE,SAAS,SAAS,MAAuB;CACvC,MAAM,OAAO,SAAS,UAAU;CAChC,MAAM,QAAwB,EAAE;CAChC,IAAI,QAAQ,KAAK,KAAK,KAAK;AAE3B,MAAK,MAAM,UAAU,CAAC,KAAK,WAAW,KAAK,CACzC,MAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,OAAO,0BAA0B,OAAO,CAAC,CAChF,MAAK,MAAM,MAAM;EAAC,KAAK;EAAO,KAAK;EAAK,KAAK;EAAI,CAC/C,KAAI,OAAO,MAAM,cAAc,OAAO,MAAM;AAC1C,UAAQ,MAAM,QAAQ,KAAK,KAAK,GAAG,EAAE,GAAG;AACxC,MAAI,WAAW,KAAM,OAAM,OAAO,KAAK,MAAM,aAAa,KAAK,MAAM,QAAQ;;AAGrF,QAAO;EAAE;EAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI;EAAE;EAAO,KAAK,SAAS,KAAsB;EAAE;;AAGjG,SAAS,WAAW,MAAa,MAAa;AAC5C,KAAI,KAAK,UAAU,KAAK,SAAS,QAAQ,KAAK,KAAK,MAAM,CAAE,QAAO;AAClE,KAAI,OAAO,eAAe,KAAK,KAAK,KAAK,OAAO,eAAe,KAAK,KAAK,CAAE,QAAO;AAElF,MAAK,MAAM,OAAO,KAAK,MACrB,KAAI,OAAO,KAAK,SAAS,KAAK,MAAM,SAAS,KAAK,MAAM,KAAM,QAAO;AAEvE,QAAO;;;;;;;;AAST,SAAS,OAA0C,IAAY,SAAe;CAC5E,IAAI,QAAQ,QAAQ,IAAI,GAAG;AAE3B,KAAI,CAAC,MAAO,SAAQ,IAAI,IAAK,QAAQ,EAAE,CAAE;CAEzC,MAAM,SAAkC,EAAE,GAAG,SAAS;CACtD,MAAM,0BAAU,IAAI,KAAY;CAChC,MAAM,UAAsB,EAAE;CAC9B,IAAI,UAAU;AAEd,QAAO;AAEP,MAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,QAAQ,EAAE;AAClD,MAAI,CAAC,QAAQ,KAAK,CAAE;EAEpB,MAAM,OAAO,MAAM;AAEnB,MAAI,MAAM,SAAS,KAAM;EAEzB,MAAM,OAAO,SAAS,KAAK;AAE3B,MAAI,CAAC,QAAQ,CAAC,WAAW,MAAM,KAAK,EAAE;AACpC,OAAI,KAAM,SAAQ,KAAK;IAAE;IAAI;IAAM,MAAM,KAAK;IAAuB,MAAM;IAAM,CAAC;AAClF,SAAM,QAAQ;AACd;;AAGF,MAAI;AACF,QAAK,MAAM,SAAS,MAAM,KAAK,MAAuB,MAAM,KAAK,IAAI,CAAE,SAAQ,IAAI,MAAM;AACzF,aAAU;AACV,SAAM,QAAQ;IAAE,GAAG;IAAM,MAAM,KAAK;IAAM;AAC1C,UAAO,QAAQ,KAAK;WACb,OAAO;AACd,WAAQ,MAAM,MAAM;AACpB,WAAQ,KAAK;IAAE;IAAI;IAAM,MAAM,KAAK;IAAuB,MAAM;IAAM,CAAC;AACxE,SAAM,QAAQ;;;AAIlB,KAAI,QAAS,UAAS;AAEtB,MAAK,MAAM,SAAS,QAAS,KAAI,SAAS,MAAM,EAAE,MAAO,OAAM,OAAO,QAAQ;AAE9E,MAAK,MAAM,SAAS,QAClB,MAAK,MAAM,YAAY,UACrB,KAAI;AACF,WAAS,MAAM;UACR,OAAO;AACd,UAAQ,MAAM,MAAM;;AAG1B,QAAO;;;;;;;AAQT,SAAS,SAAS,UAAiD;AACjE,WAAU,IAAI,SAAS;AACvB,cAAa,KAAK,UAAU,OAAO,SAAS"}
1
+ {"version":3,"file":"hot.js","names":[],"sources":["../src/hot.ts"],"sourcesContent":["import { rechain } from './component';\nimport { event } from './observable';\nimport {\n State,\n GETTERS,\n LATEST,\n METHODS,\n SETUP,\n UNBIND,\n classify,\n compute,\n type Handler\n} from './state';\n\ninterface Entry {\n type: Function;\n shape: string;\n kinds: Record<string, 'get' | 'accessor' | 'fn'>;\n own: Handler[];\n}\n\ninterface Replaced {\n /** Module id the class was accepted under. */\n id: string;\n /** Local declaration name of the class. */\n name: string;\n /** Class live instances belong to. */\n prev: State.Extends;\n /** Class that took its place. */\n next: State.Extends;\n}\n\nconst define = Object.defineProperty;\n\n/** Method implementations replaced by a hot patch. */\nconst PAST = new WeakSet<Function>();\n\n/** Live instances, tracked once hot patching is enabled. */\nlet LIVE: Set<WeakRef<State>> | undefined;\n\n/** Bootstrapped subclasses of each class, tracked once hot patching is enabled. */\nconst SUBCLASSES = new WeakMap<Function, Set<State.Extends>>();\n\nconst MODULES = new Map<string, Record<string, Entry>>();\nconst LISTENERS = new Set<(event: Replaced) => void>();\nconst REFRESH = Symbol.for('@expressive/mvc.refresh');\nconst PRIVATE = /(?:^|[\\s;{}*])#[\\w$]+(?=[\\s=;(}])/;\n\n/** Begin tracking live instances, so a hot patch can reach them. */\nfunction track() {\n if (LIVE) return;\n\n LIVE = new Set();\n\n State.on({\n type(type) {\n const parent = Object.getPrototypeOf(type);\n let children = SUBCLASSES.get(parent);\n if (!children) SUBCLASSES.set(parent, (children = new Set()));\n children.add(type);\n },\n setup(state) {\n const ref = new WeakRef(state);\n LIVE!.add(ref);\n return () => LIVE!.delete(ref);\n }\n });\n}\n\n/**\n * Move the members of `next` onto `prev`, which keeps its identity. Returns the\n * live instances of `prev`, each needing a refresh.\n */\nfunction patch(prev: State.Extends, next: State.Extends, own: Handler[]): State[] {\n const proto = prev.prototype;\n const incoming = Object.getOwnPropertyDescriptors(next.prototype);\n const keys = METHODS.get(prev);\n const getters = GETTERS.get(prev);\n const methods = new Map<string, Function>();\n const knownKeys = new Set(keys?.keys());\n const knownGetters = new Set(getters?.keys());\n\n let setup = SETUP.get(prev);\n\n for (const handler of own) setup!.delete(handler);\n for (const handler of handlers(next)) {\n if (!setup) SETUP.set(prev, (setup = new Set()));\n setup.add(handler);\n }\n\n for (const key of Reflect.ownKeys(next)) {\n if (key == 'prototype' || key == 'length' || key == 'name') continue;\n if (Object.getOwnPropertyDescriptor(prev, key)?.configurable !== false)\n define(prev, key, Object.getOwnPropertyDescriptor(next, key)!);\n }\n\n const removed = new Set<string>();\n\n for (const key of Object.getOwnPropertyNames(proto))\n if (key != 'constructor' && !(key in incoming)) {\n const bind = keys?.get(key);\n\n if (bind && Object.getOwnPropertyDescriptor(proto, key)!.get === bind) {\n PAST.add(UNBIND.get(bind));\n keys!.delete(key);\n }\n\n removed.add(key);\n Reflect.deleteProperty(proto, key);\n getters?.delete(key);\n }\n\n for (const [key, desc] of Object.entries(incoming)) {\n if (key == 'constructor') continue;\n\n const current = Object.getOwnPropertyDescriptor(proto, key);\n\n if (typeof desc.value == 'function') methods.set(key, desc.value);\n if (current?.configurable === false) {\n if (current.writable) (proto as any)[key] = desc.value;\n continue;\n }\n\n if (current?.get && keys?.get(key) === current.get)\n PAST.add(UNBIND.get(current.get));\n\n const getter = getters?.get(key);\n\n if (getter) LATEST.set(getter, desc.get!);\n\n define(proto, key, { ...desc, configurable: true });\n }\n\n if (keys) {\n for (let T: State.Extends = prev; ; T = Object.getPrototypeOf(T)) {\n for (const handler of SETUP.get(T) || [])\n if (handler.type) handler.type(prev);\n\n if (T === State) break;\n }\n\n classify(prev, keys, getters!);\n }\n\n const live: State[] = [];\n\n for (const ref of LIVE!) {\n const state = ref.deref();\n\n if (!state) LIVE!.delete(ref);\n else if (state instanceof prev) live.push(state);\n }\n\n const descendants = new Set([prev, ...live.map((state) => state.constructor as State.Extends)]);\n\n for (const type of descendants) for (const child of SUBCLASSES.get(type) || []) descendants.add(child);\n\n descendants.delete(prev);\n\n for (const type of descendants) {\n const inherit = METHODS.get(type)!;\n const computed = GETTERS.get(type)!;\n\n for (const [key, bind] of keys!) if (!knownKeys.has(key) && !inherit.has(key)) inherit.set(key, bind);\n for (const [key, get] of getters!) if (!knownGetters.has(key) && !computed.has(key)) computed.set(key, get);\n for (const key of removed)\n if (!(key in type.prototype)) {\n inherit.delete(key);\n computed.delete(key);\n }\n }\n\n for (const state of live) {\n for (const [key, value] of methods) {\n const desc = Object.getOwnPropertyDescriptor(state, key);\n\n if (!desc) continue;\n if (desc.set) desc.set.call(state, value);\n else if (PAST.has(UNBIND.get(desc.value))) delete (state as any)[key];\n }\n\n for (const key of removed)\n if (PAST.has(UNBIND.get(Object.getOwnPropertyDescriptor(state, key)?.value))) delete (state as any)[key];\n\n for (const [key, get] of GETTERS.get(state.constructor)!)\n if (!knownGetters.has(key) && get === getters!.get(key)) compute.call(state, get, key);\n }\n\n return live;\n}\n\n/** Lifecycle handlers registered on a class itself. */\nfunction handlers(type: State.Extends): Handler[] {\n return [...(SETUP.get(type) || [])];\n}\n\nfunction isState(value: unknown): value is State.Extends {\n return typeof value == 'function' && value.prototype instanceof State;\n}\n\n/** What a patch cannot carry: class source less its members, and member kinds. */\nfunction describe(type: Function): Entry {\n const text = Function.prototype.toString;\n const kinds: Entry['kinds'] = {};\n let shape = text.call(type);\n\n for (const target of [type.prototype, type])\n for (const [key, desc] of Object.entries(Object.getOwnPropertyDescriptors(target)))\n for (const fn of [desc.value, desc.get, desc.set])\n if (typeof fn == 'function' && fn !== type) {\n shape = shape.replace(text.call(fn), '');\n if (target !== type) kinds[key] = desc.set ? 'accessor' : desc.get ? 'get' : 'fn';\n }\n\n shape = shape.replace(/\\s+/g, ' ').replace(/__vite_ssr_import_\\d+__/g, '__vite_ssr_import__');\n\n return { type, shape, kinds, own: handlers(type as State.Extends) };\n}\n\nfunction compatible(prev: Entry, next: Entry) {\n if (prev.shape !== next.shape || PRIVATE.test(next.shape)) return false;\n if (Object.getPrototypeOf(prev.type) !== Object.getPrototypeOf(next.type)) return false;\n\n for (const key in next.kinds)\n if (key in prev.kinds && prev.kinds[key] !== next.kinds[key]) return false;\n\n return true;\n}\n\n/**\n * Keep a module's State classes stable across runs. A class seen before is\n * patched with its replacement and returned in its place, refreshing live\n * instances; one whose shape or parent changed is returned as-is, and\n * reported to `replaced` listeners before `accept` returns.\n */\nfunction accept<T extends Record<string, unknown>>(id: string, classes: T): T {\n let known = MODULES.get(id);\n\n if (!known) MODULES.set(id, (known = {}));\n\n const output: Record<string, unknown> = { ...classes };\n const refresh = new Set<State>();\n const replace: Replaced[] = [];\n let patched = false;\n\n track();\n\n for (const [name, type] of Object.entries(classes)) {\n if (!isState(type)) continue;\n\n const prev = known[name];\n\n if (prev?.type === type) continue;\n\n const next = describe(type);\n\n if (!prev || !compatible(prev, next)) {\n if (prev) replace.push({ id, name, prev: prev.type as State.Extends, next: type });\n known[name] = next;\n continue;\n }\n\n try {\n for (const state of patch(prev.type as State.Extends, type, prev.own)) refresh.add(state);\n patched = true;\n known[name] = { ...next, type: prev.type };\n output[name] = prev.type;\n } catch (error) {\n console.error(error);\n replace.push({ id, name, prev: prev.type as State.Extends, next: type });\n known[name] = next;\n }\n }\n\n if (patched) rechain();\n\n for (const state of refresh) event(state, REFRESH);\n\n for (const event of replace)\n for (const listener of LISTENERS)\n try {\n listener(event);\n } catch (error) {\n console.error(error);\n }\n\n return output as T;\n}\n\n/**\n * Observe classes `accept` replaced instead of patching. Fires synchronously\n * inside `accept`, while the module re-runs, so a host can retire instances of\n * `prev` before anything resolves the module again.\n */\nfunction replaced(listener: (event: Replaced) => void): () => void {\n LISTENERS.add(listener);\n return () => void LISTENERS.delete(listener);\n}\n\nexport { accept, replaced };\nexport type { Replaced };\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  import { Context } from "./context.js";
2
2
  import { State, unbind } from "./state.js";
3
- import { Caught } from "./caught.js";
4
3
  import { Component } from "./component.js";
5
4
  import { pending } from "./dispatch.js";
6
5
  import { def } from "./field/def.js";
@@ -9,4 +8,4 @@ import { has } from "./field/has.js";
9
8
  import { map } from "./field/map.js";
10
9
  import { ref } from "./field/ref.js";
11
10
  import { set } from "./field/set.js";
12
- export { Caught, Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
11
+ export { Component, Context, State, def, State as default, get, has, map, pending, ref, set, unbind };
package/dist/index.js CHANGED
@@ -1,6 +1,5 @@
1
- import { Caught } from "./caught.js";
2
- import { State, unbind } from "./state.js";
3
1
  import { pending } from "./dispatch.js";
2
+ import { State, unbind } from "./state.js";
4
3
  import { Context } from "./context.js";
5
4
  import { def } from "./field/def.js";
6
5
  import { set } from "./field/set.js";
@@ -15,5 +14,5 @@ import { ref } from "./field/ref.js";
15
14
  var src_default = State;
16
15
 
17
16
  //#endregion
18
- export { Caught, Component, Context, State, def, src_default as default, get, has, map, pending, ref, set, unbind };
17
+ export { Component, Context, State, def, src_default as default, get, has, map, pending, ref, set, unbind };
19
18
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["export { def } from './field/def';\nexport { get } from './field/get';\nexport { has } from './field/has';\nexport { map } from './field/map';\nexport { set } from './field/set';\nexport { ref } from './field/ref';\n\nimport { State } from './state';\n\nexport { State, unbind } from './state';\n\n/** @deprecated Import `{ State }` as a named export. Adapter-augmented `State.*` types are not visible through the default alias. */\nexport default State;\nexport { Context } from './context';\nexport { Component } from './component';\nexport { pending } from './dispatch';\nexport { Caught } from './caught';\n"],"mappings":";;;;;;;;;;;;;;AAYA,kBAAe"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["export { def } from './field/def';\nexport { get } from './field/get';\nexport { has } from './field/has';\nexport { map } from './field/map';\nexport { set } from './field/set';\nexport { ref } from './field/ref';\n\nimport { State } from './state';\n\nexport { State, unbind } from './state';\n\n/** @deprecated Import `{ State }` as a named export. Adapter-augmented `State.*` types are not visible through the default alias. */\nexport default State;\nexport { Context } from './context';\nexport { Component } from './component';\nexport { pending } from './dispatch';\n"],"mappings":";;;;;;;;;;;;;AAYA,kBAAe"}
@@ -1,3 +1,2 @@
1
- import { Fragment, jsxDEV } from "./runtime.js";
2
- import { JSX } from "./jsx-runtime.js";
1
+ import { Fragment, JSX, jsxDEV } from "./jsx-runtime.js";
3
2
  export { Fragment, type JSX, jsxDEV };
@@ -1,3 +1,3 @@
1
- import { Fragment, jsxDEV } from "./runtime.js";
1
+ import { Fragment, jsxDEV } from "./jsx-runtime.js";
2
2
 
3
3
  export { Fragment, jsxDEV };
@@ -1,12 +1,85 @@
1
- import { Fragment, Host, jsx, jsxs } from "./runtime.js";
2
- import { Component } from "./component.js";
1
+ import { Component, compose } from "./component.js";
3
2
 
4
3
  //#region src/jsx-runtime.d.ts
4
+ /**
5
+ * Per-adapter interpretation manifest. Each adapter augments this interface to
6
+ * declare how it renders; the first member is `node` - the element type produced
7
+ * by `Component.render` (surfaced as `Component.Node`) - alongside `intrinsics`,
8
+ * the host's tag map (surfaced as `JSX.IntrinsicElements`), `elementClass`,
9
+ * the instance a class must construct to render as an element, and optionally
10
+ * `element`, further element types the host renders (joined into
11
+ * `JSX.ElementType`).
12
+ *
13
+ * ```ts
14
+ * declare module '@expressive/mvc/jsx-runtime' {
15
+ * interface Host {
16
+ * node: React.ReactNode;
17
+ * intrinsics: React.JSX.IntrinsicElements;
18
+ * elementClass: React.Component<any, any>;
19
+ * }
20
+ * }
21
+ * ```
22
+ *
23
+ * Only one adapter is expected per compilation; two augmenting the same member
24
+ * with different types in the same build would conflict - by design.
25
+ */
26
+ interface Host {}
27
+ /**
28
+ * Host runtime, registered by an adapter (e.g. `@expressive/react`) as an
29
+ * import side effect. One host per build - a second registration with a
30
+ * different runtime throws.
31
+ *
32
+ * Members are ambient host capabilities: plain functions the host uniquely
33
+ * owns, callable outside render - element mechanics always, plus optional
34
+ * extras that fall back sanely when absent. Hook-shaped (render-resident)
35
+ * capabilities do not belong here; those live with the adapter.
36
+ */
37
+ interface HostRuntime {
38
+ childrenOf(children: unknown): Component.Node[];
39
+ isElement(node: unknown): boolean;
40
+ jsx(type: unknown, props: object, key?: unknown): Component.Node;
41
+ jsxDEV?(type: unknown, props: object, key?: unknown, isStatic?: boolean, source?: object, self?: unknown): Component.Node;
42
+ jsxs(type: unknown, props: object, key?: unknown): Component.Node;
43
+ propsOf(node: unknown): Record<string, unknown>;
44
+ typeOf(node: unknown): unknown;
45
+ Fragment: unknown;
46
+ }
47
+ /**
48
+ * Agnostic Fragment sentinel. The runtime entries translate it to the host's
49
+ * Fragment on element creation; `typeOf` translates back, so identity checks
50
+ * against this value hold for fragments from either pragma.
51
+ */
52
+ declare const Fragment: unique symbol;
53
+ /**
54
+ * Register the host runtime. Idempotent for the same runtime - re-registering
55
+ * picks up members added since (e.g. an optional dev seam). Element mechanics
56
+ * the host leaves unset keep defaults that throw a setup-pointing error;
57
+ * `jsxDEV` is routed around at the call site instead.
58
+ */
59
+ declare function host(runtime: HostRuntime): void;
60
+ declare function jsx(type: unknown, props: object, key?: unknown): Component.Node;
61
+ declare function jsxs(type: unknown, props: object, key?: unknown): Component.Node;
62
+ /** Dev-transpiled element creation. Hosts without a `jsxDEV` of their own fall
63
+ * back to the production entries (prod-only host under a dev build). */
64
+ declare function jsxDEV(type: unknown, props: object, key?: unknown, isStatic?: boolean, source?: object, self?: unknown): Component.Node;
65
+ /** Flatten `children` to an array of nodes, per the host's semantics. */
66
+ declare function childrenOf(children: unknown): Component.Node[];
67
+ /** Is `node` a host element? */
68
+ declare function isElement(node: unknown): boolean;
69
+ /** Element type of `node`; host Fragments surface as the agnostic `Fragment`. */
70
+ declare function typeOf(node: unknown): unknown;
71
+ /** Props carried by element `node`. */
72
+ declare function propsOf(node: unknown): Record<string, unknown>;
5
73
  declare namespace JSX {
6
74
  type Element = Component.Node;
7
- type ElementType = keyof IntrinsicElements | ((props: any) => Component.Node) | (abstract new (...args: any[]) => ElementClass);
75
+ type ElementType = keyof IntrinsicElements | ((props: any) => Component.Node) | (new (...args: any[]) => Host extends {
76
+ elementClass: infer I;
77
+ } ? I : ElementClass) | (Host extends {
78
+ element: infer T;
79
+ } ? T : never);
8
80
  /**
9
- * Gates class element types on the `render` contract alone - requiring full
81
+ * Class instance contract when no host declares `elementClass`. Gates on the
82
+ * `render` contract alone - requiring full
10
83
  * `Component` assignability trips contravariance on `props` members (e.g.
11
84
  * the `is` callback narrows per subclass), rejecting every subclass.
12
85
  */
@@ -32,5 +105,5 @@ declare namespace JSX {
32
105
  } ? T : {};
33
106
  }
34
107
  //#endregion
35
- export { Fragment, JSX, jsx, jsxs };
108
+ export { Fragment, Host, HostRuntime, JSX, childrenOf, compose, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
36
109
  //# sourceMappingURL=jsx-runtime.d.ts.map
@@ -1,3 +1,70 @@
1
- import { Fragment, jsx, jsxs } from "./runtime.js";
1
+ import { compose } from "./component.js";
2
2
 
3
- export { Fragment, jsx, jsxs };
3
+ //#region src/jsx-runtime.ts
4
+ /**
5
+ * Agnostic Fragment sentinel. The runtime entries translate it to the host's
6
+ * Fragment on element creation; `typeOf` translates back, so identity checks
7
+ * against this value hold for fragments from either pragma.
8
+ */
9
+ const Fragment = Symbol.for("@expressive/mvc.Fragment");
10
+ /** Default for seams only a registered host can provide. */
11
+ function absent() {
12
+ throw new Error("No JSX host is registered for @expressive/mvc. Import a host adapter (e.g. '@expressive/react') before anything renders - typically as the first import of your application entry module.");
13
+ }
14
+ const HOST = {
15
+ childrenOf: absent,
16
+ isElement: absent,
17
+ jsx: absent,
18
+ jsxs: absent,
19
+ propsOf: absent,
20
+ typeOf: absent,
21
+ Fragment
22
+ };
23
+ let registered;
24
+ /**
25
+ * Register the host runtime. Idempotent for the same runtime - re-registering
26
+ * picks up members added since (e.g. an optional dev seam). Element mechanics
27
+ * the host leaves unset keep defaults that throw a setup-pointing error;
28
+ * `jsxDEV` is routed around at the call site instead.
29
+ */
30
+ function host(runtime) {
31
+ 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.");
32
+ registered = runtime;
33
+ Object.assign(HOST, runtime);
34
+ }
35
+ /** Translate the agnostic Fragment sentinel to the host's Fragment. */
36
+ function hostType(type) {
37
+ return type === Fragment ? HOST.Fragment : type;
38
+ }
39
+ function jsx(type, props, key) {
40
+ return HOST.jsx(hostType(type), props, key);
41
+ }
42
+ function jsxs(type, props, key) {
43
+ return HOST.jsxs(hostType(type), props, key);
44
+ }
45
+ /** Dev-transpiled element creation. Hosts without a `jsxDEV` of their own fall
46
+ * back to the production entries (prod-only host under a dev build). */
47
+ function jsxDEV(type, props, key, isStatic, source, self) {
48
+ return HOST.jsxDEV ? HOST.jsxDEV(hostType(type), props, key, isStatic, source, self) : isStatic ? jsxs(type, props, key) : jsx(type, props, key);
49
+ }
50
+ /** Flatten `children` to an array of nodes, per the host's semantics. */
51
+ function childrenOf(children) {
52
+ return HOST.childrenOf(children);
53
+ }
54
+ /** Is `node` a host element? */
55
+ function isElement(node) {
56
+ return HOST.isElement(node);
57
+ }
58
+ /** Element type of `node`; host Fragments surface as the agnostic `Fragment`. */
59
+ function typeOf(node) {
60
+ const type = HOST.typeOf(node);
61
+ return type === HOST.Fragment ? Fragment : type;
62
+ }
63
+ /** Props carried by element `node`. */
64
+ function propsOf(node) {
65
+ return HOST.propsOf(node);
66
+ }
67
+
68
+ //#endregion
69
+ export { Fragment, childrenOf, compose, host, isElement, jsx, jsxDEV, jsxs, propsOf, typeOf };
70
+ //# sourceMappingURL=jsx-runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx-runtime.ts"],"sourcesContent":["import type { Component } from './component';\n\nexport { compose } 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`), `elementClass`,\n * the instance a class must construct to render as an element, and optionally\n * `element`, further element types the host renders (joined into\n * `JSX.ElementType`).\n *\n * ```ts\n * declare module '@expressive/mvc/jsx-runtime' {\n * interface Host {\n * node: React.ReactNode;\n * intrinsics: React.JSX.IntrinsicElements;\n * elementClass: React.Component<any, any>;\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\nexport declare namespace JSX {\n type Element = Component.Node;\n type ElementType =\n | keyof IntrinsicElements\n | ((props: any) => Component.Node)\n | (new (...args: any[]) => Host extends { elementClass: infer I } ? I : ElementClass)\n | (Host extends { element: infer T } ? T : never);\n /**\n * Class instance contract when no host declares `elementClass`. Gates on the\n * `render` contract alone - requiring full\n * `Component` assignability trips contravariance on `props` members (e.g.\n * the `is` callback narrows per subclass), rejecting every subclass.\n */\n interface ElementClass { render(props?: any): Component.Node }\n interface ElementAttributesProperty { props: {} }\n interface ElementChildrenAttribute { children: {} }\n interface IntrinsicAttributes { key?: string | number | null }\n /**\n * Host tag manifest, via the {@link Host} seam. Resolves to `{}` until an\n * adapter augments `Host` with `intrinsics` - agnostic code is\n * components-only by design, since it cannot know what tags a host renders.\n */\n type IntrinsicElements =\n Host extends { intrinsics: infer T extends object } ? T : {};\n}\n"],"mappings":";;;;;;;;AAsDA,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"}