@wcstack/state 2.6.1 → 3.0.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.
Files changed (64) hide show
  1. package/README.ja.md +91 -46
  2. package/README.md +93 -46
  3. package/dist/auto.min.js +1 -1
  4. package/dist/auto.min.js.map +1 -1
  5. package/dist/define.d.ts +295 -0
  6. package/dist/define.js +1 -0
  7. package/dist/index.d.ts +252 -94
  8. package/dist/index.esm.js +1 -23477
  9. package/dist/index.esm.js.map +1 -1
  10. package/dist/manifest.esm.js +21 -37
  11. package/dist/parser.d.ts +37 -39
  12. package/dist/parser.esm.js +147 -1153
  13. package/dist/split/chunks/binder.js +2 -0
  14. package/dist/split/chunks/binder.js.map +1 -0
  15. package/dist/split/chunks/checkDependency.js +2 -0
  16. package/dist/split/chunks/checkDependency.js.map +1 -0
  17. package/dist/split/chunks/diagnosticsHooks.js +2 -0
  18. package/dist/split/chunks/diagnosticsHooks.js.map +1 -0
  19. package/dist/split/chunks/errorGuidance.js +2 -0
  20. package/dist/split/chunks/errorGuidance.js.map +1 -0
  21. package/dist/split/chunks/features.d.ts +29 -0
  22. package/dist/split/chunks/filterRegistry.js +2 -0
  23. package/dist/split/chunks/filterRegistry.js.map +1 -0
  24. package/dist/split/chunks/getAllPropertyDescriptors.js +2 -0
  25. package/dist/split/chunks/getAllPropertyDescriptors.js.map +1 -0
  26. package/dist/split/chunks/lifecycleHooks.js +2 -0
  27. package/dist/split/chunks/lifecycleHooks.js.map +1 -0
  28. package/dist/split/chunks/mount.js +2 -0
  29. package/dist/split/chunks/mount.js.map +1 -0
  30. package/dist/split/chunks/pathDiagnostics.js +2 -0
  31. package/dist/split/chunks/pathDiagnostics.js.map +1 -0
  32. package/dist/split/chunks/registerComponents.js +2 -0
  33. package/dist/split/chunks/registerComponents.js.map +1 -0
  34. package/dist/split/chunks/setAll.js +2 -0
  35. package/dist/split/chunks/setAll.js.map +1 -0
  36. package/dist/split/chunks/version.js +2 -0
  37. package/dist/split/chunks/version.js.map +1 -0
  38. package/dist/split/chunks/watchRuntime.js +2 -0
  39. package/dist/split/chunks/watchRuntime.js.map +1 -0
  40. package/dist/split/core.d.ts +1417 -0
  41. package/dist/split/core.js +2 -0
  42. package/dist/split/core.js.map +1 -0
  43. package/dist/split/features/devtools.d.ts +9 -0
  44. package/dist/split/features/devtools.js +2 -0
  45. package/dist/split/features/devtools.js.map +1 -0
  46. package/dist/split/features/diagnostics.d.ts +11 -0
  47. package/dist/split/features/diagnostics.js +2 -0
  48. package/dist/split/features/diagnostics.js.map +1 -0
  49. package/dist/split/features/formats.d.ts +10 -0
  50. package/dist/split/features/formats.js +2 -0
  51. package/dist/split/features/formats.js.map +1 -0
  52. package/dist/split/features/recursion.d.ts +9 -0
  53. package/dist/split/features/recursion.js +2 -0
  54. package/dist/split/features/recursion.js.map +1 -0
  55. package/dist/split/features/scopes.d.ts +10 -0
  56. package/dist/split/features/scopes.js +2 -0
  57. package/dist/split/features/scopes.js.map +1 -0
  58. package/dist/split/features/ssr.d.ts +9 -0
  59. package/dist/split/features/ssr.js +2 -0
  60. package/dist/split/features/ssr.js.map +1 -0
  61. package/dist/split/features/temporal.d.ts +9 -0
  62. package/dist/split/features/temporal.js +2 -0
  63. package/dist/split/features/temporal.js.map +1 -0
  64. package/package.json +13 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watchRuntime.js","sources":["../../../../../src/scan/scanRegistry.ts","../../../../../src/scan/eventReset.ts","../../../../../src/scan/initialValue.ts","../../../../../src/scan/scanReport.ts","../../../../../src/stream/lastNotified.ts","../../../../../src/stream/activeStateElements.ts","../../../../../src/stream/streamRegistry.ts","../../../../../src/watch/chainDepth.ts","../../../../../src/watch/computedSnapshots.ts","../../../../../src/watch/prevValues.ts","../../../../../src/watch/watchRegistry.ts","../../../../../src/watch/processWatchDeclaration.ts","../../../../../src/watch/addressHooks.ts","../../../../../src/watch/rowLanding.ts","../../../../../src/scan/scanRuntime.ts","../../../../../src/watch/watchRuntime.ts"],"sourcesContent":["/**\n * scan/scanRegistry.ts\n *\n * `$scan` の registry(docs/state-scan-design.md §2)。\n *\n * `$watch` の registry とは別台帳にする。watch の registry はパスにつき entry 1 個\n * (`Map<string, IWatchEntry>`)なので、同じパスを `$watch` と `$scan` が並んで\n * 見る形・同じ `from` を 2 つの scan が畳む形を載せられない。\n *\n * 寿命は `$watch` と揃える: `_state` 再セットで作り直し、切断では消さない\n * (発火対象から外れるのは watch runtime の active 集合側)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport type { IScanEntry, IScanRegistry } from \"./types\";\n\nconst registryByStateElement: WeakMap<IStateElement, IScanRegistry> = new WeakMap();\n\n/**\n * drain 側の粗いゲート: 発火対象(watch runtime の active 集合)に居て、`from` か `resetOn` を持つ state。\n *\n * 空のあいだ watch runtime は scan の収集ループに入らない = `$scan` を使っていない画面の drain に、\n * バッチのアドレスごとの registry 引きを載せない。registry の有無ではなく active 集合への出入り\n * (watch/watchRegistry.ts の addActiveWatchStateElement / deactivateWatch / clearWatchRegistry)で\n * 数えるので、`$scan` を持つ state を DOM から外せば(SPA のページ差し替え)ゲートは閉じ、\n * 再接続(startWatch)で開き直す。strong Set でも、切断と再セットで必ず外れるので GC を妨げない\n * (active 集合と同じ不変条件)。\n */\nconst drainActive = new Set<IStateElement>();\n\n/**\n * enqueue 側のゲート: 発火対象に居て、`resetOn` を持つ `on` scan がある state(scan/eventReset.ts)。\n * 空のあいだ updater の enqueue は整数比較 1 回で抜ける。数え方は drainActive と同じ。\n */\nconst eventResetActive = new Set<IStateElement>();\n\nfunction hasDrainWork(registry: IScanRegistry): boolean {\n return registry.byFromPath.size > 0 || registry.byResetPath.size > 0;\n}\n\nfunction hasEventResetWork(registry: IScanRegistry): boolean {\n return registry.eventResetByPath.size > 0;\n}\n\nfunction pushEntry(map: Map<string, IScanEntry[]>, key: string, entry: IScanEntry): void {\n const list = map.get(key);\n if (typeof list === \"undefined\") {\n map.set(key, [entry]);\n } else {\n list.push(entry);\n }\n}\n\n/** registry を置換登録する(`_state` セッターから)。 */\nexport function setScanRegistry(stateElement: IStateElement, entries: readonly IScanEntry[]): IScanRegistry {\n clearScanRegistry(stateElement);\n const byFromPath = new Map<string, IScanEntry[]>();\n const byResetPath = new Map<string, IScanEntry[]>();\n const eventResetByPath = new Map<string, IScanEntry[]>();\n for (const entry of entries) {\n if (entry.source.kind === \"path\") {\n pushEntry(byFromPath, entry.source.path, entry);\n }\n for (const path of entry.resetOn) {\n pushEntry(byResetPath, path, entry);\n if (entry.source.kind === \"event\") {\n pushEntry(eventResetByPath, path, entry);\n }\n }\n }\n const registry: IScanRegistry = { entries: new Set(entries), byFromPath, byResetPath, eventResetByPath };\n registryByStateElement.set(stateElement, registry);\n return registry;\n}\n\nexport function getScanRegistry(stateElement: IStateElement): IScanRegistry | undefined {\n return registryByStateElement.get(stateElement);\n}\n\n/**\n * registry を削除する(`_state` 再セットで作り直す前)。ゲートからも外す — 同じ再セットの\n * startWatch が新しい registry で数え直す(`_state` セッターは registry を作った後に\n * clearWatchRegistry → startWatch を通る)。\n */\nexport function clearScanRegistry(stateElement: IStateElement): void {\n deactivateScanGates(stateElement);\n registryByStateElement.delete(stateElement);\n}\n\n/** 発火対象に載った(watch/watchRegistry.ts の addActiveWatchStateElement 専用)。冪等。 */\nexport function activateScanGates(stateElement: IStateElement): void {\n const registry = registryByStateElement.get(stateElement);\n if (typeof registry === \"undefined\") {\n return;\n }\n if (hasDrainWork(registry)) {\n drainActive.add(stateElement);\n }\n if (hasEventResetWork(registry)) {\n eventResetActive.add(stateElement);\n }\n}\n\n/** 発火対象から外れた(切断・再セット)。 */\nexport function deactivateScanGates(stateElement: IStateElement): void {\n drainActive.delete(stateElement);\n eventResetActive.delete(stateElement);\n}\n\n/**\n * drain で発火すべき scan(`from` か `resetOn`)を持つか。\n * `startWatch` が発火対象集合へ載せる判定に使う(`on` だけの scan は drain を要らない)。\n */\nexport function hasScanDrainWork(stateElement: IStateElement): boolean {\n const registry = registryByStateElement.get(stateElement);\n return typeof registry !== \"undefined\" && hasDrainWork(registry);\n}\n\n/** 発火対象に居て、`resetOn` を持つ `on` scan がある state か(enqueue の保留判定)。 */\nexport function hasActiveScanEventReset(stateElement: IStateElement): boolean {\n return eventResetActive.has(stateElement);\n}\n\nexport function getScanDrainGateCount(): number {\n return drainActive.size;\n}\n\nexport function getScanEventResetGateCount(): number {\n return eventResetActive.size;\n}\n","/**\n * scan/eventReset.ts\n *\n * `on` scan の `resetOn` を「書き込みの時点」で効かせる台帳(docs/state-scan-design.md D6)。\n *\n * `on` の fold は出来事のその場で同期に書く。一方 `resetOn` のパスはバッチに載って drain の\n * 終わりにしか見えない。drain で reset するだけだと、reset の書き込みから drain までに起きた\n * 出来事 — その書き込みの binding 適用で要素が同期に dispatch したものを含む — まで消える。\n *\n * そこで reset の要求を enqueue の時点で entry に保留する。\n * - 保留中に来た出来事の fold は `initial` から畳み、出力の書き込みが通ったら保留を消す\n * (fold の throw・thenable・書き込みの throw なら残す)。\n * - 保留が残ったまま drain に来たら、scan runtime が出力を `initial` に戻して保留を消す。\n * これで「書き込みより後の出来事は reset 後の出力に畳まれる」順序になる。\n *\n * 保留は「その書き込みが載ったバッチの drain で initial に戻す」予約なので、寿命をそのバッチに\n * 揃える。drain がそのバッチの scan を発火しない(書き込みの後・drain の前に切断された・連鎖深さの\n * 上限で打ち切った・先行 fold が同期に切断や再セットをした)なら保留を捨てる。残すと、後の無関係な\n * 出来事が突然 `initial` から畳み始める。同じ条件の `from` の scan は reset しない(発火しない)ので、\n * それに揃える。保留は entry ごとの 1 bit でどのバッチの書き込みかを持たないので、同じ `resetOn` の\n * パスが次のバッチ向けに既に積まれていれば捨てない — その保留は次のバッチの drain が使う。\n *\n * updater(enqueue 側)から呼ばれるので updater を import しない(watch/chainDepth.ts と同じ理由)。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { getScanEventResetGateCount, getScanRegistry, hasActiveScanEventReset } from \"./scanRegistry\";\nimport type { IScanEntry } from \"./types\";\n\nconst pendingResets: WeakSet<IScanEntry> = new WeakSet();\n\n/**\n * 保留中の entry の数。捨てる走査(discardPendingScanResets)のゲート。保留は enqueue の直後の drain で\n * 使うか捨てるか次のバッチへ持ち越すので、ふつうは 0。enqueue のゲート(発火対象の state)と別に持つのは、\n * 書き込みの後・drain の前に切断された state がゲートから外れても、その保留は drain で捨てるため。\n */\nlet pendingResetCount = 0;\n\n/** このアドレスを `resetOn` に持つ `on` scan(無ければ undefined) */\nfunction eventResetEntriesAt(absAddress: IAbsoluteStateAddress): readonly IScanEntry[] | undefined {\n return getScanRegistry(absAddress.absolutePathInfo.stateElement)\n ?.eventResetByPath.get(absAddress.absolutePathInfo.pathInfo.path);\n}\n\n/**\n * 書き込みの enqueue を記録する(updater 専用)。\n * `resetOn` を持つ `on` scan が発火対象の state に 1 つも無ければ(そうした state を DOM から外した後を含む)、\n * 整数比較 1 回で抜ける。\n */\nexport function noteEnqueueForScanReset(absAddress: IAbsoluteStateAddress): void {\n if (getScanEventResetGateCount() === 0) {\n return;\n }\n // 発火対象でない state(切断中・初期化中・SSR)の書き込みは reset しない — drain 側と同じ扱い\n if (!hasActiveScanEventReset(absAddress.absolutePathInfo.stateElement)) {\n return;\n }\n const entries = eventResetEntriesAt(absAddress);\n if (typeof entries === \"undefined\") {\n return;\n }\n for (const entry of entries) {\n markPendingScanReset(entry);\n }\n}\n\n/**\n * 保留を立てる。enqueue の記録(上)と、`_state` 再セットで旧宣言の保留を同じ出力の `on` scan へ\n * 引き継ぐとき(processScanDeclaration.ts の registerScans)だけが呼ぶ。\n */\nexport function markPendingScanReset(entry: IScanEntry): void {\n if (!pendingResets.has(entry)) {\n pendingResets.add(entry);\n pendingResetCount++;\n }\n}\n\nexport function hasPendingScanReset(entry: IScanEntry): boolean {\n return pendingResets.has(entry);\n}\n\n/** 保留があれば消して true を返す。 */\nexport function consumePendingScanReset(entry: IScanEntry): boolean {\n if (!pendingResets.delete(entry)) {\n return false;\n }\n pendingResetCount--;\n return true;\n}\n\n/** 保留中の entry の数(テストと診断用)。 */\nexport function getPendingScanResetCount(): number {\n return pendingResetCount;\n}\n\n/**\n * drain がバッチの scan を発火しないとき、そのバッチが載せた保留を捨てる。\n * `firing` はこの drain で scan を発火する state の集合。null はバッチ全体を発火しない\n * (連鎖深さの上限)。`isQueued` は「次のバッチ向けに、この state のこのパスが積まれているか」\n * (updater を import しないので呼び出し側から受け取る)。\n */\nexport function discardPendingScanResets(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n firing: ReadonlySet<IStateElement> | null,\n isQueued: (stateElement: IStateElement, path: string) => boolean,\n): void {\n if (pendingResetCount === 0) {\n return;\n }\n for (const absAddress of batch) {\n const stateElement = absAddress.absolutePathInfo.stateElement;\n if (firing?.has(stateElement) === true) {\n continue;\n }\n const entries = eventResetEntriesAt(absAddress);\n if (typeof entries === \"undefined\") {\n continue;\n }\n for (const entry of entries) {\n if (!entry.resetOn.some((path) => isQueued(stateElement, path))) {\n consumePendingScanReset(entry);\n }\n }\n }\n}\n","/**\n * scan/initialValue.ts\n *\n * 出力に置く `initial` の複製と、「出力がいま `initial` と同じ値か」の判定\n * (docs/state-scan-design.md D6 / D7・§5-9)。\n *\n * 実体化と reset が宣言の `initial` をそのまま置くと、出力が `initial` の間に子パスへ書いた値\n * (`$watch` ハンドラの注記など)が宣言の `initial` 自体を書き換える。以後の reset はその値に戻し、\n * 出力が同じ参照なので書き込みもしない。そこで plain なデータは複製して置く。\n *\n * plain なデータ: プロトタイプが `Array.prototype` / `Object.prototype` / null で、凍結されておらず、\n * 自前のプロパティがすべて列挙できる文字列キーのデータプロパティ(配列は添字と `length` だけ)の\n * 配列とオブジェクト。判定は property descriptor で行い、getter を実行しない。それ以外\n * (getter / setter・Symbol キー・列挙できないプロパティ・配列の追加プロパティ・Array のサブクラス・\n * 凍結された値・関数・クラスのインスタンス・Map / Set・Date・DOM ノード)は参照のまま置く。\n *\n * 「reset で出力が既に `initial` なら書かない」は、参照ではなく値で見る。plain なデータは中身を再帰で\n * 比べ、それ以外は同一性で比べる。訪れた対を覚えるので、形の違う循環でも止まる。\n */\n\ntype PlainKind = \"array\" | \"object\";\n\nconst ARRAY_INDEX = /^(?:0|[1-9]\\d*)$/;\n\nfunction isEnumerableData(target: object, key: string): boolean {\n const descriptor = Object.getOwnPropertyDescriptor(target, key) as PropertyDescriptor;\n return descriptor.enumerable === true && \"value\" in descriptor;\n}\n\n/** plain なデータならその種類、そうでなければ null(参照のまま扱う)。 */\nfunction plainKind(value: unknown): PlainKind | null {\n if (typeof value !== \"object\" || value === null || Object.isFrozen(value)) {\n return null;\n }\n const proto: unknown = Object.getPrototypeOf(value);\n if (Array.isArray(value)) {\n const plainArray = proto === Array.prototype && Reflect.ownKeys(value).every(\n (key) => key === \"length\" || (typeof key === \"string\" && ARRAY_INDEX.test(key) && isEnumerableData(value, key)),\n );\n return plainArray ? \"array\" : null;\n }\n const plainObject = (proto === Object.prototype || proto === null) && Reflect.ownKeys(value).every(\n (key) => typeof key === \"string\" && isEnumerableData(value, key),\n );\n return plainObject ? \"object\" : null;\n}\n\nfunction cloneValue(value: unknown, copies: Map<object, unknown>): unknown {\n const kind = plainKind(value);\n if (kind === null) {\n return value;\n }\n const source = value as Record<string, unknown>;\n const known = copies.get(source);\n if (typeof known !== \"undefined\") {\n return known;\n }\n let copy: Record<string, unknown>;\n if (kind === \"array\") {\n // 穴はそのまま(添字のキーだけを写す)\n copy = new Array((value as unknown[]).length) as unknown as Record<string, unknown>;\n } else {\n copy = Object.getPrototypeOf(value) === null ? Object.create(null) : {};\n }\n copies.set(source, copy);\n for (const key of Object.keys(source)) {\n copy[key] = cloneValue(source[key], copies);\n }\n return copy;\n}\n\n/** plain なデータを再帰で複製する。それ以外の値は参照のまま返す(循環と共有参照も保つ)。 */\nexport function cloneInitial<T>(initial: T): T {\n return cloneValue(initial, new Map()) as T;\n}\n\nfunction sameValue(current: unknown, initial: unknown, compared: Map<object, Set<object>>): boolean {\n if (Object.is(current, initial)) {\n return true;\n }\n // 宣言側の種類を先に決め、配列の長さ・キーの数が違えば、出力側の descriptor を見ずに抜ける\n // (大きく積み上がった出力を空の initial と比べるたびに、出力の大きさに比例させない)\n const kind = plainKind(initial);\n if (kind === null || typeof current !== \"object\" || current === null) {\n return false;\n }\n const left = current as Record<string, unknown>;\n const right = initial as Record<string, unknown>;\n if (kind === \"array\") {\n if (!Array.isArray(current) || current.length !== (initial as unknown[]).length) {\n return false;\n }\n } else if (Array.isArray(current) || Object.keys(left).length !== Object.keys(right).length) {\n return false;\n }\n if (plainKind(current) !== kind) {\n return false;\n }\n // 訪れた対を出力側の値ごとの集合で覚える。形の違う循環(自己循環と 2 段の循環など)でも、同じ対の 2 回目で止まる\n let seen = compared.get(left);\n if (typeof seen === \"undefined\") {\n seen = new Set();\n compared.set(left, seen);\n } else if (seen.has(right)) {\n return true;\n }\n seen.add(right);\n if (kind === \"array\") {\n for (let index = 0; index < (current as unknown[]).length; index++) {\n if (!sameValue(left[index], right[index], compared)) {\n return false;\n }\n }\n return true;\n }\n return Object.keys(right).every(\n (key) => Object.prototype.hasOwnProperty.call(left, key) && sameValue(left[key], right[key], compared),\n );\n}\n\n/** 出力が `initial` と同じ値か(plain なデータは中身を、それ以外は同一性を比べる)。 */\nexport function isSameAsInitial(current: unknown, initial: unknown): boolean {\n return sameValue(current, initial, new Map());\n}\n\n/**\n * 実体化・fold・reset が出力に置いた関数値と、その出力名(docs/state-scan-design.md D7・§5-9 の C5-14)。\n *\n * fold が関数を返す出力は、再セットの宣言検査で state の関数値として見える。それがこの出力に置いた値なら\n * 累積で、メソッドとの衝突ではない。どの世代の state オブジェクトに書かれたか(世代を進めた後に throw した\n * 再セットの後は、新しい `__state` にだけ書かれる)に依らず判定できるよう、値そのものを記録する。\n * 関数は WeakMap のキーなので、出力から外れれば記録ごと回収される。\n */\nconst outputNamesByFunction: WeakMap<object, Set<string>> = new WeakMap();\n\n/** 出力に置いた値を記録する(関数のときだけ残す)。 */\nexport function recordOutputValue(name: string, value: unknown): void {\n if (typeof value !== \"function\") {\n return;\n }\n const names = outputNamesByFunction.get(value);\n if (typeof names === \"undefined\") {\n outputNamesByFunction.set(value, new Set([name]));\n } else {\n names.add(name);\n }\n}\n\n/** その関数値を、実体化・fold・reset がこの出力に置いたことがあるか。 */\nexport function wasPlacedOnOutput(name: string, value: unknown): boolean {\n return typeof value === \"function\" && outputNamesByFunction.get(value)?.has(name) === true;\n}\n","/**\n * scan/scanReport.ts\n *\n * `$scan` の失敗の報告(docs/state-scan-design.md D4 / D5)。\n *\n * 値の読み・fold・出力の書き込みの例外は scan 側で閉じる(drain リスナーと event-token の\n * emit ループを他の機構と共有しているため)。閉じた事実を console と devtools の両方に出す。\n * devtools には `$watch` と同じ `state:watch-error` を path `$scan.<出力名>` で流し、phase は\n * 直し方で分ける: 値を読めなかった(`evaluate`)・fold が契約を破った(`fold`)・出力を\n * 書けなかった(`write`)。\n */\n\nimport { STATE_SCAN_NAME } from \"../define\";\nimport { devtoolsSink } from \"../platform/devtoolsSink\";\n\n/** 失敗の種類。原因も直し方も違うので console の文言を分ける */\nexport type ScanFailure = \"read-source\" | \"read-output\" | \"threw\" | \"returned-promise\" | \"write\";\n\ntype ScanPhase = \"evaluate\" | \"fold\" | \"write\";\n\nconst SCAN_FAILURE_MESSAGE: Readonly<Record<ScanFailure, (name: string) => string>> = {\n \"read-source\": (name) =>\n `${STATE_SCAN_NAME} could not read a \"from\" value for \"${name}\". That landing was not folded; the other landings of the batch still were.`,\n \"read-output\": (name) => `${STATE_SCAN_NAME} could not read the output \"${name}\". Nothing was folded or written.`,\n threw: (name) => `${STATE_SCAN_NAME} fold for \"${name}\" threw. The output was not written.`,\n \"returned-promise\": (name) =>\n `${STATE_SCAN_NAME} fold for \"${name}\" returned a Promise. fold must be synchronous and return the next value; the output was not written.`,\n write: (name) => `${STATE_SCAN_NAME} could not write the output \"${name}\".`,\n};\n\nconst SCAN_FAILURE_PHASE: Readonly<Record<ScanFailure, ScanPhase>> = {\n \"read-source\": \"evaluate\",\n \"read-output\": \"evaluate\",\n threw: \"fold\",\n \"returned-promise\": \"fold\",\n write: \"write\",\n};\n\nfunction sendToDevtools(name: string, phase: ScanPhase, error: unknown): void {\n if (devtoolsSink !== null) {\n devtoolsSink({\n type: \"state:watch-error\",\n phase,\n path: `${STATE_SCAN_NAME}.${name}`,\n error,\n });\n }\n}\n\nexport function reportScanError(name: string, error: unknown, failure: ScanFailure): void {\n console.error(`[@wcstack/state] ${SCAN_FAILURE_MESSAGE[failure](name)}`, error);\n sendToDevtools(name, SCAN_FAILURE_PHASE[failure], error);\n}\n\nexport function isThenable(value: unknown): boolean {\n return value !== null\n && (typeof value === \"object\" || typeof value === \"function\")\n && typeof (value as { then?: unknown }).then === \"function\";\n}\n\n/**\n * fold が thenable を返した(同期契約違反)。書き込まずに報告し、\n * 後から reject されても unhandled rejection にしない。\n */\nexport function reportScanThenable(name: string, value: unknown): void {\n (value as PromiseLike<unknown>).then(undefined, () => undefined);\n reportScanError(\n name,\n new TypeError(`${STATE_SCAN_NAME} fold for \"${name}\" returned a Promise. fold must be synchronous and return the next value.`),\n \"returned-promise\",\n );\n}\n\nconst lateGetterReported: WeakSet<object> = new WeakSet();\n\n/**\n * 宣言時には plain だった `from` が、接ぎ木(ボリュームのアクセサ登録)で後から getter に\n * なった(設計書 D5 後段)。getter の再評価回数を畳まないよう、その scan を止める。\n * entry につき 1 回だけ報告する。fold を適用しないと決めた失敗なので devtools の phase は `fold`。\n */\nexport function reportLateGetterSource(entry: object, name: string, path: string): void {\n if (lateGetterReported.has(entry)) {\n return;\n }\n lateGetterReported.add(entry);\n const message = `[wcs/scan-source-computed] ${STATE_SCAN_NAME} entry \"${name}\" from \"${path}\" is now backed by a getter ` +\n `(registered after the declaration, e.g. by a volume). A getter re-evaluates whenever its inputs change, ` +\n `so this scan stopped folding. Fold the plain value the getter reads instead.`;\n console.error(`[@wcstack/state] ${message}`);\n sendToDevtools(name, \"fold\", new Error(message));\n}\n","/**\n * stream/lastNotified.ts\n *\n * 「最後に通知した観測値」台帳 — DOM binding / $updatedCallback(観測層)が\n * 最後に見た status・error(docs/state-streams-design.md §4-3)。\n *\n * 通知の same-value 判定を entry フィールドとの比較で行うと、再 set\n * (clearStreamRegistry → 新 entry 生成)を跨いだ陳腐化を検出できない\n * (error 表示中に再 set すると新 entry は error=null で生まれるため\n * null → null と誤判定して $postUpdate が落ち、DOM に旧 error が残る)。\n * そのため通知 dedup は entry の寿命ではなく stateElement の寿命で持つ\n * (ただし再 set で新宣言から消えた名前のエントリは pruneLastNotified で削除する —\n * 同名にしか dedup は要らず、放置すると台帳が単調増加するため)。\n * 未通知(初回)の基準値は宣言直後の観測初期値と同じ { idle, null }。\n *\n * さらに abortAllStreams(§5-1)は registry entry を通知なしで idle / null に\n * 直接ミューテーションするため、観測層が「台帳の値」と「idle / null」の\n * どちらを見たか確定できなくなる(binding / computed の fresh 読みは通知が\n * なくても他パスの drain で走る)。その乖離フィールドは invalidateLastNotified\n * で UNCERTAIN に無効化し、次回 updateStreamStatus の同値判定が必ず\n * 「変化あり」になるようにする(再接続ウィンドウ内の idle 描画が恒久陳腐化\n * しないための不変条件、§4-3)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport type { StreamStatus } from \"./types\";\n\n/**\n * 無通知ミューテーション後の「観測値が確定できない」印。\n * どの実値とも一致しないため、次回の通知 dedup(`!==` / `Object.is`)を強制的に解除する。\n */\nconst UNCERTAIN: unique symbol = Symbol(\"wcs-stream-last-notified-uncertain\");\n\nexport interface ILastNotified {\n status: StreamStatus | typeof UNCERTAIN;\n error: unknown;\n}\n\nconst lastNotifiedByStateElement = new WeakMap<IStateElement, Map<string, ILastNotified>>();\n\n/**\n * 最後に通知した観測値を返す。未通知なら基準値 { idle, null }。\n */\nexport function getLastNotified(stateElement: IStateElement, name: string): ILastNotified {\n return (\n lastNotifiedByStateElement.get(stateElement)?.get(name) ?? { status: \"idle\", error: null }\n );\n}\n\n/**\n * 通知した観測値を記録する(updateStreamStatus が $postUpdate 発行と同時に呼ぶ)。\n */\nexport function setLastNotified(\n stateElement: IStateElement,\n name: string,\n status: StreamStatus,\n error: unknown,\n): void {\n let lastMap = lastNotifiedByStateElement.get(stateElement);\n if (typeof lastMap === \"undefined\") {\n lastMap = new Map();\n lastNotifiedByStateElement.set(stateElement, lastMap);\n }\n lastMap.set(name, { status, error });\n}\n\n/**\n * 再 set(clearStreamRegistry → processStreamsDeclaration)後に呼び、新宣言に\n * 存在しない名前の台帳エントリを削除する。台帳は stateElement の寿命で生存するが\n * (§4-3 の再 set・再接続跨ぎ dedup)、それが必要なのは同名エントリのみで、\n * 旧宣言にしか無い名前は以後どの通知経路(updateStreamStatus)からも参照されない。\n * prune しないと、再 set のたびに異なる stream 名を使うステートで台帳が\n * stateElement の寿命の間単調増加する。\n * 既知の許容: prune 後に同名を再宣言した場合、dedup は基準値 { idle, null } から\n * やり直しになる(宣言削除時の binding 陳腐化が §4-4 の既知エッジである以上、\n * 再宣言は新規宣言と同じ扱いでよい)。\n */\nexport function pruneLastNotified(stateElement: IStateElement, liveNames: ReadonlySet<string>): void {\n const lastMap = lastNotifiedByStateElement.get(stateElement);\n if (typeof lastMap === \"undefined\") {\n return;\n }\n for (const name of lastMap.keys()) {\n if (!liveNames.has(name)) {\n lastMap.delete(name);\n }\n }\n}\n\n/**\n * 無通知ミューテーション(abortAllStreams の idle / null 直接書き換え)の直後に呼び、\n * 台帳のうちミューテーション後の値と一致しないフィールドを UNCERTAIN に無効化する。\n * 一致しているフィールド(観測層がどちらを見ても同じ値)は dedup を維持する\n * (例: error が null のままなら再接続時に $streamError.<name> の余計な通知は出ない)。\n */\nexport function invalidateLastNotified(stateElement: IStateElement, name: string): void {\n const lastMap = lastNotifiedByStateElement.get(stateElement);\n if (typeof lastMap === \"undefined\") {\n return;\n }\n const last = lastMap.get(name);\n if (typeof last === \"undefined\") {\n // 未通知: 基準値 { idle, null } はミューテーション後の値と一致するため乖離しない\n return;\n }\n lastMap.set(name, {\n status: last.status === \"idle\" ? last.status : UNCERTAIN,\n error: Object.is(last.error, null) ? null : UNCERTAIN,\n });\n}\n\nexport const __private__ = {\n lastNotifiedByStateElement,\n UNCERTAIN,\n};\n","/**\n * stream/activeStateElements.ts\n *\n * 起動中(startStreams 済み・未切断)の stateElement の列挙用 Set\n * (docs/state-streams-design.md §3-2)。\n *\n * streamRegistry の WeakMap は列挙不能のため、updater の drain リスナーが\n * 「どの stateElement の entry と batch を交差させるか」を知るには\n * 列挙可能な strong Set が別途必要になる。lastNotified.ts と同じ\n * 「import 循環回避の小モジュール」パターン\n * (streamRegistry → activeStateElements ← streamRuntime の一方向依存に保つ)。\n *\n * リーク防止の不変条件(strong Set が切断済み要素の GC を妨げないための連動):\n * - add は startStreams(streamRuntime.ts)だけが行う\n * (eager 起動=connect 時、および接続中の `_state` 再 set 時の再起動)。\n * - delete は abortAllStreams / clearStreamRegistry(streamRegistry.ts)が行う。\n * disconnect(disconnectedCallback → abortAllStreams)と `_state` 再 set\n * (clearStreamRegistry → processStreamsDeclaration → 接続中なら startStreams で\n * 再 add)の両経路が必ずここを通るため、「Set に居る = 接続中かつ起動済み」が\n * 常に保たれ、切断済み stateElement への強参照は残らない。\n * 設計書 §3-2 の「未接続(disconnect 済み)の stateElement の entry は restart\n * しない」はこの不変条件で担保される。\n */\n\nimport type { IStateElement } from \"../components/types\";\n\nconst activeStateElements = new Set<IStateElement>();\n\n/**\n * 起動中 stateElement として登録する(startStreams 専用。不変条件はモジュールヘッダ参照)。\n */\nexport function addActiveStateElement(stateElement: IStateElement): void {\n activeStateElements.add(stateElement);\n}\n\n/**\n * 起動中 stateElement から外す(abortAllStreams / clearStreamRegistry 専用)。\n */\nexport function deleteActiveStateElement(stateElement: IStateElement): void {\n activeStateElements.delete(stateElement);\n}\n\n/**\n * 起動中 stateElement を列挙する(drain リスナーの交差判定用)。\n */\nexport function getActiveStateElements(): ReadonlySet<IStateElement> {\n return activeStateElements;\n}\n\nexport const __private__ = {\n activeStateElements,\n};\n","/**\n * stream/streamRegistry.ts\n *\n * `$streams` の registry(docs/state-streams-design.md §2-1 / §5)。\n * eventTokenRegistry と対称の WeakMap registry。\n *\n * - status / error の正本は registry entry(state オブジェクト上に実プロパティは持たない)。\n * - disconnect 時は abortAllStreams(abort のみ・registry 保持)、\n * `_state` 再 set 時のみ clearStreamRegistry(abort + 全削除)。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport { deleteActiveStateElement } from \"./activeStateElements\";\nimport { invalidateLastNotified } from \"./lastNotified\";\nimport type { IStreamEntry } from \"./types\";\n\nconst registryByStateElement: WeakMap<IStateElement, Map<string, IStreamEntry>> = new WeakMap();\n\n/**\n * stream entry 群を置換登録する(`_state` セッターからの再構築で丸ごと差し替える)。\n */\nexport function setStreamEntries(stateElement: IStateElement, entries: Map<string, IStreamEntry>): void {\n registryByStateElement.set(stateElement, entries);\n}\n\n/**\n * 登録済みの stream entry 群を返す。未登録なら空 Map を返す(registry への登録はしない)。\n */\nexport function getStreamEntries(stateElement: IStateElement): Map<string, IStreamEntry> {\n return registryByStateElement.get(stateElement) ?? new Map<string, IStreamEntry>();\n}\n\n/**\n * 全 stream を abort して idle に戻す(設計書 §5-1)。registry は保持する。\n *\n * disconnectedCallback(切断時)に呼ばれるため、status / error の反映は\n * proxy / $postUpdate を使わず entry への直接ミューテーションで行う\n * (切断済みで binding 更新は不要かつ rootNode が無い)。\n *\n * 無通知ミューテーションは「最後に通知した観測値」台帳(stream/lastNotified.ts)\n * と registry を乖離させるため、同時に台帳側を invalidate する。これを怠ると\n * 再接続ウィンドウ内の fresh 読み(他パスの drain での getter 再計算など)が\n * 描画した idle に対し、restart の updateStreamStatus(\"active\") が切断前の\n * 通知値と同値判定されて skip され、DOM が恒久的に陳腐化する(設計書 §4-3)。\n */\nexport function abortAllStreams(stateElement: IStateElement): void {\n // 依存駆動 restart の対象から外す(切断済み stateElement は restart しない、\n // 設計書 §3-2。add 側は startStreams — stream/activeStateElements.ts の\n // リーク防止不変条件を参照)。registry の有無に関わらず必ず外す。\n deleteActiveStateElement(stateElement);\n const entries = registryByStateElement.get(stateElement);\n if (typeof entries === \"undefined\") {\n return;\n }\n for (const entry of entries.values()) {\n entry.controller?.abort();\n entry.controller = null;\n entry.status = \"idle\";\n entry.error = null;\n invalidateLastNotified(stateElement, entry.name);\n }\n}\n\n/**\n * 全 stream を abort したうえで registry から削除する(`_state` 再 set 時の再配線用、設計書 §5-2)。\n */\nexport function clearStreamRegistry(stateElement: IStateElement): void {\n abortAllStreams(stateElement);\n // abortAllStreams が既に delete 済みだが、「clear = 全削除でも必ず restart 対象から\n // 外れる」不変条件を将来の abortAllStreams の変更から独立に保証するため明示的に呼ぶ。\n deleteActiveStateElement(stateElement);\n registryByStateElement.delete(stateElement);\n}\n\nexport const __private__ = {\n registryByStateElement,\n};\n","/**\n * watch/chainDepth.ts\n *\n * `$watch` ハンドラ起点の書き込み連鎖の深さを数える台帳\n * (docs/state-watch-hook-design.md §7-2)。\n *\n * watch ハンドラ内の書き込みは新しい microtask バッチを作るため、伝播 context の\n * hop 上限(MAX_PROPAGATION_HOPS)のガードが効かない。かつ書き込み先が動的なので、\n * `$streams` のような「宣言時の自己依存検出」も使えない。よって実行時に数える。\n *\n * updater(enqueue 側)と watchRuntime(発火側)の両方から参照されるため、\n * **依存ゼロの葉モジュール**にして循環 import を避ける(platform/devtoolsSink.ts と同じ方針)。\n *\n * 数え方: ハンドラ実行中に enqueue が起きたときだけ「次のバッチはこの連鎖の続き」と\n * マークする。ハンドラが何も書かなければ次のバッチは深さ 0 に戻るので、利用者操作が\n * 何度続いても深さは伸びない。\n */\n\n/** ハンドラ実行中に立つ「今の連鎖の深さ + 1」。0 なら watch 起点ではない */\nlet firingDepth = 0;\n\n/** 次に drain されるバッチの深さ */\nlet pendingDepth = 0;\n\n/** watch の発火フェーズ開始(watchRuntime 専用) */\nexport function beginWatchFiring(depth: number): void {\n firingDepth = depth + 1;\n}\n\n/** watch の発火フェーズ終了(watchRuntime 専用。必ず finally で呼ぶ) */\nexport function endWatchFiring(): void {\n firingDepth = 0;\n}\n\n/**\n * 書き込みの enqueue を記録する(updater 専用)。\n * ハンドラ実行中でなければ何もしない = 通常の書き込みに深さは付かない。\n */\nexport function noteEnqueueForWatchChain(): void {\n if (firingDepth > pendingDepth) {\n pendingDepth = firingDepth;\n }\n}\n\n/** 次バッチの深さを消費する(watchRuntime 専用。読んだらリセット) */\nexport function consumeWatchChainDepth(): number {\n const depth = pendingDepth;\n pendingDepth = 0;\n return depth;\n}\n\nexport const __private__ = {\n reset(): void {\n firingDepth = 0;\n pendingDepth = 0;\n },\n};\n","/**\n * watch/computedSnapshots.ts\n *\n * watch 対象の computed(getter)の「前回評価値」台帳\n * (docs/state-watch-hook-design.md §5)。\n *\n * getter は `setByAddress` を通らないので、スカラ書き込み用の旧値台帳\n * (watch/prevValues.ts)には載らない。`prev` を渡すには前回の評価値を\n * **バッチを跨いで**保持する必要があり、こちらは drain ごとにクリアしない。\n *\n * 寿命は stateElement 単位(WeakMap)。`_state` 再 set では宣言ごと作り直すため\n * 破棄する。切断では破棄しない —— 再接続時の初回評価が上書きするので、\n * 残っていても害がなく、registry を保持する扱いとも揃う。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\n\nconst snapshotsByStateElement: WeakMap<IStateElement, Map<IAbsoluteStateAddress, unknown>> = new WeakMap();\n\nexport function getComputedSnapshot(\n stateElement: IStateElement,\n absAddress: IAbsoluteStateAddress,\n): unknown {\n return snapshotsByStateElement.get(stateElement)?.get(absAddress);\n}\n\nexport function setComputedSnapshot(\n stateElement: IStateElement,\n absAddress: IAbsoluteStateAddress,\n value: unknown,\n): void {\n let snapshots = snapshotsByStateElement.get(stateElement);\n if (typeof snapshots === \"undefined\") {\n snapshots = new Map<IAbsoluteStateAddress, unknown>();\n snapshotsByStateElement.set(stateElement, snapshots);\n }\n snapshots.set(absAddress, value);\n}\n\n/** `_state` 再 set で宣言ごと作り直すときに破棄する */\nexport function clearComputedSnapshots(stateElement: IStateElement): void {\n snapshotsByStateElement.delete(stateElement);\n}\n\nexport const __private__ = {\n snapshotsByStateElement,\n};\n","/**\n * watch/prevValues.ts\n *\n * `$watch` ハンドラへ渡す `prev`(バッチ開始時点の値)の台帳\n * (docs/state-watch-hook-design.md §4-1)。\n *\n * 記録するのは **watch 宣言済みパスへの書き込みだけ**、かつ **バッチ内で最初の 1 回だけ**\n * (first-write-wins)。したがって `prev` は「そのバッチが始まる前の値」、`cur` は\n * drain 時点の確定値になる。同一バッチ内の中間値は観測できない(§3-4)。\n *\n * 値の出どころは same-value guard が既に読んでいる旧値であり、watch のために\n * 追加の getByAddress は行わない(§10)。その帰結として:\n * - 参照型(object / array)は guard が素通しするので `prev` は undefined\n * - `config.sameValueGuard = false` でも undefined\n * - `$postUpdate` / stream の status 通知は setByAddress を通らないので undefined\n *\n * 台帳は drain 終端(watchRuntime)でクリアされる。drain の外で書き込まれた分が\n * 次のバッチへ持ち越されることはない。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\n\nconst prevValueByAbsoluteStateAddress: Map<IAbsoluteStateAddress, unknown> = new Map();\n\n/**\n * バッチ内で最初の書き込みのときだけ旧値を記録する(first-write-wins)。\n */\nexport function recordPrevValue(absAddress: IAbsoluteStateAddress, oldValue: unknown): void {\n if (prevValueByAbsoluteStateAddress.has(absAddress)) {\n return;\n }\n prevValueByAbsoluteStateAddress.set(absAddress, oldValue);\n}\n\n/**\n * 記録済みの旧値を返す。記録が無ければ undefined(§4-1 の「prev を保証しない」経路)。\n */\nexport function getPrevValue(absAddress: IAbsoluteStateAddress): unknown {\n return prevValueByAbsoluteStateAddress.get(absAddress);\n}\n\n/**\n * 旧値が記録済みか(記録された undefined と、記録が無いことを区別する)。\n */\nexport function hasPrevValue(absAddress: IAbsoluteStateAddress): boolean {\n return prevValueByAbsoluteStateAddress.has(absAddress);\n}\n\n/**\n * 台帳をクリアする(drain 終端で必ず呼ぶ)。\n */\nexport function clearPrevValues(): void {\n prevValueByAbsoluteStateAddress.clear();\n}\n\nexport const __private__ = {\n prevValueByAbsoluteStateAddress,\n};\n","/**\n * watch/watchRegistry.ts\n *\n * `$watch` の registry と、drain リスナーの走査元になる「発火対象の stateElement 集合」\n * (docs/state-watch-hook-design.md §9)。\n *\n * `$streams` は registry(delete 側)と runtime(add 側)が相互に依存するため\n * active 集合を stream/activeStateElements.ts へ切り出しているが、`$watch` は\n * **add が State のライフサイクル側、delete が registry 側**で、runtime は読むだけの\n * 一方向依存になる。よって循環せず、1 モジュールにまとめられる。\n *\n * リーク防止の不変条件(strong Set が切断済み要素の GC を妨げないための連動):\n * - add は `startWatch`(`State.connectedCallback` の $connectedCallback 完了後、および\n * 接続中の `_state` 再 set)だけが行い、**宣言が 1 つも無い stateElement は入れない**。\n * - delete は `deactivateWatch`(disconnectedCallback)/`clearWatchRegistry`(`_state`\n * 再 set)だけが行う。\n * どちらの経路も必ずここを通るため「Set に居る = 接続中かつ宣言済み」が保たれる。\n * この「宣言済み」の側が崩れると、`$watch` 未使用アプリの drain にも収集ループが乗る\n * (ゼロコスト契約、docs/state-watch-hook-design.md §10)。\n * `$scan` の drain / enqueue のゲート(scan/scanRegistry.ts)も同じ出入りで数える。\n */\n\nimport type { IStateElement } from \"../components/types\";\nimport { activateScanGates, deactivateScanGates } from \"../scan/scanRegistry\";\nimport type { IWatchEntry } from \"./types\";\n\nconst registryByStateElement: WeakMap<IStateElement, Map<string, IWatchEntry>> = new WeakMap();\n\n/**\n * ボリュームが追記した watch entry(webComponent/volume.ts — 接頭辞翻訳済み・\n * ハンドラは chroot 包装済み)。ルート自身の宣言(上の registry・_state 再 set で\n * 丸ごと差し替わる)とはライフサイクルが違うため別台帳にする。同じ翻訳パスに\n * ルートの宣言とボリュームの宣言が並ぶことも、複数ボリュームが同名パスに並ぶことも\n * ある(配列・登録順)。\n */\nconst volumeEntriesByStateElement: WeakMap<IStateElement, Map<string, IWatchEntry[]>> = new WeakMap();\nconst activeStateElements = new Set<IStateElement>();\n\n/**\n * 未登録時に返す共有の空 Map。\n *\n * ここで毎回 `new Map()` すると、drain の収集ループが「バッチのアドレス 1 個につき\n * Map を 1 個」アロケートすることになる(発火対象だが宣言を持たない stateElement を\n * 通る経路)。読み出ししかしない返り値なので 1 個を使い回す。\n */\nconst EMPTY_ENTRIES: ReadonlyMap<string, IWatchEntry> = new Map<string, IWatchEntry>();\n\n/**\n * watch entry 群を置換登録する(`_state` セッターからの再構築で丸ごと差し替える)。\n */\nexport function setWatchEntries(stateElement: IStateElement, entries: Map<string, IWatchEntry>): void {\n registryByStateElement.set(stateElement, entries);\n}\n\n/**\n * 登録済みの watch entry 群を返す。未登録なら共有の空 Map を返す\n * (registry への登録はしない。返り値は読み出し専用)。\n */\nexport function getWatchEntries(stateElement: IStateElement): ReadonlyMap<string, IWatchEntry> {\n return registryByStateElement.get(stateElement) ?? EMPTY_ENTRIES;\n}\n\n/**\n * 発火対象として登録する(`startWatch` 専用。不変条件はモジュールヘッダ参照)。\n */\nexport function addActiveWatchStateElement(stateElement: IStateElement): void {\n activeStateElements.add(stateElement);\n activateScanGates(stateElement);\n}\n\n/**\n * 発火対象を列挙する(drain リスナーの early return 判定用)。\n */\nexport function getActiveWatchStateElements(): ReadonlySet<IStateElement> {\n return activeStateElements;\n}\n\n/**\n * 発火対象から外す(切断時)。**registry は保持する。**\n *\n * `$streams` の abortAllStreams と同じ二段構えで、切断は「発火しなくなる」だけにする。\n * registry まで捨てると、再接続(connectedCallback → startWatch)で宣言を作り直す経路が\n * 無い(`_state` セッターは初回ロード時にしか走らない)ため、watch が二度と発火しない。\n */\nexport function deactivateWatch(stateElement: IStateElement): void {\n activeStateElements.delete(stateElement);\n deactivateScanGates(stateElement);\n}\n\n/**\n * registry から削除し、発火対象からも外す(`_state` 再 set 時の再配線用)。\n */\nexport function clearWatchRegistry(stateElement: IStateElement): void {\n activeStateElements.delete(stateElement);\n deactivateScanGates(stateElement);\n registryByStateElement.delete(stateElement);\n}\n\n/** ボリュームの watch entry を追記する(置換しない)。 */\nexport function addVolumeWatchEntries(stateElement: IStateElement, entries: readonly IWatchEntry[]): void {\n let byPath = volumeEntriesByStateElement.get(stateElement);\n if (typeof byPath === \"undefined\") {\n byPath = new Map();\n volumeEntriesByStateElement.set(stateElement, byPath);\n }\n for (const entry of entries) {\n const list = byPath.get(entry.path);\n if (typeof list === \"undefined\") {\n byPath.set(entry.path, [entry]);\n } else {\n list.push(entry);\n }\n }\n}\n\nconst EMPTY_VOLUME_ENTRIES: ReadonlyMap<string, readonly IWatchEntry[]> = new Map();\n\nexport function getVolumeWatchEntries(stateElement: IStateElement): ReadonlyMap<string, readonly IWatchEntry[]> {\n return volumeEntriesByStateElement.get(stateElement) ?? EMPTY_VOLUME_ENTRIES;\n}\n\nexport const __private__ = {\n registryByStateElement,\n activeStateElements,\n};\n","/**\n * watch/processWatchDeclaration.ts\n *\n * `$watch: { \"<path>\": (cur, prev, ...indexes) => void }` 宣言マップを解析し、\n * IWatchEntry を構築して watchRegistry に一括登録する\n * (docs/state-watch-hook-design.md §2-2 / §8)。\n *\n * `$streams` の processStreamsDeclaration と対称だが、**キーが宣言名ではなくパス**である\n * ぶん検証が異なる(`.` / `*` を許可し、代わりにパスとしての妥当性を見る)。\n *\n * 依存グラフ登録(§8)がこの関数の要点:\n * `setPathInfo` は BindingSession(= DOM バインディング登録)からしか呼ばれないため、\n * 静的依存グラフに載るのは「バインドされたパス」だけである。watch を宣言しただけでは\n * walkDependency がそのパスを知らず、`items` への代入で `items.*.price` がバッチに載らない\n * = ハンドラが黙って一度も発火しない。宣言時に自分で登録することでこれを塞ぐ。\n *\n * 呼び出しは stateElement の `_pathSet` クリア後・getterPaths 確定後であること\n * (State の `_state` セッターが順序を保証する)。\n */\n\nimport { getPathInfo } from \"../address/PathInfo\";\nimport type { IStateElement } from \"../components/types\";\nimport { MAX_WILDCARD_DEPTH, STATE_WATCH_NAME } from \"../define\";\nimport { LINT_HINT } from \"../errorGuidance\";\nimport { raiseError } from \"../raiseError\";\nimport type { IState } from \"../types\";\nimport { setWatchEntries } from \"./watchRegistry\";\nimport type { IWatchEntry, WatchHandler } from \"./types\";\n\n/**\n * `$watch` 宣言を registry へ反映し、監視対象パスの集合を返す。\n *\n * 宣言が無い(または空)なら **null** を返す。呼び出し側(State)はこれを\n * `watchPaths` に保持し、setByAddress のホットパスは `!== null` の分岐 1 個で\n * 抜けられる(ゼロコスト契約、§10)。\n */\n/**\n * `$watch` パスの静的検査(宣言側とボリュームの接頭辞登録 — webComponent/volume.ts —\n * で共有)。検証に通れば pathInfo を返す。\n */\nexport function assertValidWatchPath(path: string): ReturnType<typeof getPathInfo> {\n if (path.length === 0) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry name must be a non-empty state path.`);\n }\n if (path.startsWith(\"$\")) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must not start with \"$\" (reserved namespace).${LINT_HINT}`);\n }\n // 越境 watch は不採用(設計 D8)。他 state のアドレスは発火対象にしないため、\n // \"@\" 付きのパスは受け取った時点で落とす(名前次元は v2 で撤去 — 黙って発火しないより良い)。\n if (path.includes(\"@\")) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must not contain \"@\" — the name selector was removed in v2; watch only paths of the state tree.${LINT_HINT}`);\n }\n // Object.prototype の継承名は `path in state` 系の判定を汚すため一律拒否する\n // (processStreamsDeclaration と同じ防衛線)。\n if (path in Object.prototype) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must not be a property name inherited from Object.prototype (e.g. \"__proto__\", \"constructor\").`);\n }\n const pathInfo = getPathInfo(path);\n // 空セグメント(\"a..b\" / 先頭・末尾の \".\")は getPathInfo が黙って受理してしまうため、\n // ここで落とす。放置すると解決不能なアドレスを依存グラフへ登録することになる。\n for (const segment of pathInfo.segments) {\n if (segment.length === 0) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" has an empty path segment.${LINT_HINT}`);\n }\n }\n if (pathInfo.wildcardCount > MAX_WILDCARD_DEPTH) {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" exceeds the maximum wildcard depth (${MAX_WILDCARD_DEPTH}).`);\n }\n return pathInfo;\n}\n\nexport function processWatchDeclaration(\n stateElement: IStateElement,\n state: IState,\n): ReadonlySet<string> | null {\n const declared = (state as Record<string, unknown>)[STATE_WATCH_NAME];\n if (typeof declared === \"undefined\") {\n return null;\n }\n if (typeof declared !== \"object\" || declared === null) {\n // lint 側の findNonObjectWatch が「断定できる形」を同 code で検出するため誘導を付ける。\n // (LINT_HINT を付けない残りは、lint が検出しない空キー・Object.prototype 継承名・\n // ワイルドカード深度超過の 3 shape。)\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} must be an object mapping state paths to handler functions.${LINT_HINT}`);\n }\n const entries = new Map<string, IWatchEntry>();\n const paths = new Set<string>();\n let order = 0;\n for (const [path, handler] of Object.entries(declared as Record<string, unknown>)) {\n if (typeof handler !== \"function\") {\n raiseError(`[wcs/watch-declaration-invalid] ${STATE_WATCH_NAME} entry \"${path}\" must be a function.${LINT_HINT}`);\n }\n const pathInfo = assertValidWatchPath(path);\n entries.set(path, {\n path,\n pathInfo,\n handler: handler as WatchHandler,\n order: order++,\n });\n paths.add(path);\n // 依存グラフ登録(§8)。\"for\" 以外の bindingType は親 → 子の staticDependency\n // チェーンを生やすだけで listPaths / elementPaths を触らない(State.setPathInfo 参照)。\n // source=\"watch\" は存在検査の診断 code を `wcs/watch-path-missing` に切り替える\n // (watch キーの miss は raiseError にも掛からず、黙って発火しないだけになる)。\n stateElement.setPathInfo(path, \"prop\", \"watch\");\n }\n setWatchEntries(stateElement, entries);\n return paths.size > 0 ? paths : null;\n}\n","/**\n * watch/addressHooks.ts — `$watch` / `$scan` を宣言した state に付く hook(設計案 H1、S3)。\n * 宣言済みパスの `prev` 台帳(prevValues.ts)への記録を core(setByAddress)から移し、\n * どちらも宣言しない state では一切走らない。台帳を読むのは `$watch`\n * (docs/state-watch-hook-design.md §4-1)と `$scan` の `from`(docs/state-scan-design.md §2-1)。\n */\nimport { IAddressHooks } from \"../core/addressHooks\";\nimport { getPrevValue, hasPrevValue, recordPrevValue } from \"./prevValues\";\n\nexport const watchAddressHooks: IAddressHooks = {\n // same-value guard が既に読んだ旧値だけを使い、そのための追加読みはしない\n writeObserve(stateElement, path, absAddress, oldValue, hasOldValue) {\n if (!hasOldValue) {\n return;\n }\n const watchPaths = stateElement.watchPaths;\n const scanPaths = stateElement.scanPaths;\n if (watchPaths?.has(path) === true || scanPaths?.has(path) === true) {\n recordPrevValue(absAddress, oldValue);\n }\n },\n // 要素の入れ替えで行が動いた: 旧値の台帳を行に追従させる\n swapped(_stateElement, elementAbsAddress, displacedAbsAddress) {\n if (hasPrevValue(displacedAbsAddress)) {\n recordPrevValue(elementAbsAddress, getPrevValue(displacedAbsAddress));\n }\n },\n};\n","/**\n * watch/rowLanding.ts\n *\n * ワイルドカードのパスの行の着地を、drain の時点のリストの位置 1 つにつき 1 つに絞る(#274)。\n * `$watch` と `$scan` の `from` が共有する(docs/state-scan-design.md D3・§5-5)。\n *\n * バッチに載る行のアドレスは、書き込みの時点の行を指す。同じ job でその後にリストを短くした・\n * 置き換えた・途中から取り除いた・`list.*` へ要素を書き込んだと、drain の時点ではアドレスの行が\n * もうその位置に居ないことがある。添字で読むと、範囲外の読みで throw するか、その位置にいま居る\n * 別の行の値で発火する。\n */\n\nimport { createStateAddress } from \"../address/StateAddress\";\nimport type { IAbsoluteStateAddress, IPathInfo } from \"../address/types\";\nimport { isSameListIndexValue } from \"../list/createListIndex\";\nimport { getListIndexesByList, isRetiredListIndex } from \"../list/listIndexesByList\";\nimport type { IListIndex } from \"../list/types\";\nimport { listIndexAtWildcard } from \"../list/wildcardLevel\";\nimport { getByAddressSymbol } from \"../proxy/symbols\";\nimport type { IStateProxy } from \"../proxy/types\";\n\nexport interface ILandingRow {\n readonly absAddress: IAbsoluteStateAddress;\n readonly indexes: readonly number[];\n}\n\n/** 行のアドレスと、いまのリストの位置の関係 */\ntype RowPlacement = \"current\" | \"replaced\" | \"gone\";\n\n/**\n * 行の連鎖に、差分がリストから外した(退役した)行があるか。読むだけの前判定で、リストは読まない。\n * `$watch` はこれが真のヒット(か、同じ位置に重なるヒット)があるときだけ位置を引く。\n */\nexport function hasRetiredRow(listIndex: IListIndex): boolean {\n for (let row: IListIndex | null = listIndex; row !== null; row = row.parentListIndex) {\n if (isRetiredListIndex(row)) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * 行のアドレスが、いまのリストのその位置とどう関係するか。外側の段から台帳を引く。\n * 読むだけ(`$scan` の計画の相・D18)なので、台帳は観測用の `getListIndexesByList` で引き、\n * 親ポインタを修理する `resolveListIndexesByList` は使わない。\n * - `gone`: その位置に行が無い(リストを短くした・空にした・配列でなくした)か、アドレスの行を\n * 差分がリストから外した(退役した — 行を取り除いた・リストを置き換えた)。\n * - `current`: その位置の行が、アドレスの行そのものか、同じリスト要素を表す行。\n * - `replaced`: その位置には別の要素の行が居るが、アドレスの行は差分に外されていない\n * (`list.*` への要素の書き込みは、差分を通らずに台帳のその位置へ別の行を差し込む)。\n */\nfunction placementOf(state: IStateProxy, pathInfo: IPathInfo, row: ILandingRow): RowPlacement {\n // ワイルドカードのパスの着地は、収集の段階で listIndex を持つものに限っている\n const listIndex = row.absAddress.listIndex as IListIndex;\n let placement: RowPlacement = \"current\";\n let parentListIndex: IListIndex | null = null;\n for (let level = 0; level < pathInfo.wildcardCount; level++) {\n const list = state[getByAddressSymbol](createStateAddress(pathInfo.wildcardParentPathInfos[level], parentListIndex));\n // 台帳を持たない値(配列でない・空の配列)は行が無い\n const current: IListIndex | undefined = getListIndexesByList(list as readonly unknown[])?.[row.indexes[level]];\n if (typeof current === \"undefined\") {\n return \"gone\";\n }\n // `$scan` も `$watch` もルートのツリーでだけ発火するので、行の連鎖にスコープの base 段は無い(段は必ずある)\n const own = listIndexAtWildcard(listIndex, level, pathInfo.wildcardCount) as IListIndex;\n if (current !== own && !isSameListIndexValue(current, own)) {\n if (isRetiredListIndex(own)) {\n return \"gone\";\n }\n placement = \"replaced\";\n }\n parentListIndex = current;\n }\n return placement;\n}\n\n/**\n * 行の着地を、いまのリストの位置 1 つにつき 1 つに絞る。戻り値の順は、位置ごとに最初に残した行の順。\n *\n * - 位置に行が無いアドレス(行を書いてからリストを短くした・空にした)は捨てる。\n * 添字で読むと範囲外の読みで throw する。\n * - 差分がリストから外した行のアドレス(行を書いてからその行を取り除いた・リストを置き換えた)は捨てる。\n * 添字で読むと、その位置にいま居る行の値を読む — 置き換えで入った行は自分のアドレスで着地するので二重になり、\n * 位置だけが移ってきた行は変わっていないのに着地する(#274・docs/state-scan-design.md §5-5)。\n * - 同じ位置に、いまそこに居る行のアドレスと、差分に外されていない別の行のアドレス(`list.*` への要素の\n * 書き込みの前にその行へ書いた形)が並んだら前者を残す。後者しか無い位置は残し、その位置のいまの値を読ませる。\n */\nexport function selectLandedRows<T extends ILandingRow>(state: IStateProxy, pathInfo: IPathInfo, rows: readonly T[]): T[] {\n const byPosition = new Map<string, { readonly row: T; readonly rank: number }>();\n for (const row of rows) {\n const placement = placementOf(state, pathInfo, row);\n if (placement === \"gone\") {\n continue;\n }\n const rank = placement === \"current\" ? 1 : 0;\n const key = row.indexes.join(\",\");\n const kept = byPosition.get(key);\n if (typeof kept === \"undefined\" || rank > kept.rank) {\n byPosition.set(key, { row, rank });\n }\n }\n return Array.from(byPosition.values(), (kept) => kept.row);\n}\n","/**\n * scan/scanRuntime.ts\n *\n * `$scan` の drain 側の発火 — `from` と `resetOn`(docs/state-scan-design.md §2-1)。\n *\n * watch runtime の drain リスナー(`WATCH_LISTENER_PRIORITY`)から呼ばれる(D11)。\n * 発火対象集合・連鎖深さ・`prev` 台帳は `$watch` と共有する。\n *\n * 発火単位(D3): バッチに載った `from` の絶対アドレス 1 つにつき fold 1 回。\n * 同じ出力へ複数行(wildcard)が載ったバッチでは、indexes 昇順に acc を連鎖させて\n * 最後に 1 回だけ書く。開始値と `Object.is` で同じなら書かない。\n * 行の着地は、いまのリストの位置 1 つにつき 1 回に絞る(watch/rowLanding.ts の selectLandedRows — `$watch` と共有)。\n *\n * 計画と書き込みを 2 相に分ける(D18): 全 scan の次の値を読むだけで決め(planScansOnUpdateBatch)、\n * 宣言順に書く(commitScanPlans)。どちらも同じ drain の `$watch` の発火より前(D11)。\n * - 1 相で「畳んでは書く」と、ある scan の出力を `from` に取る後続の scan が、同じ drain で\n * 先行 scan が書いたばかりの(まだバッチとして届いていない)値を畳み、次のバッチで同じ値を\n * もう一度畳む — 届いていた値は取りこぼす。宣言順しだいで exactly-once が破れる。\n * - 書き込みが `$watch` より前なので、同じ drain の `$watch` ハンドラは畳んで書いた後の出力を読み、ハンドラが\n * 出力へ書いた値はそのまま残る。その代わり、出力の source を drain のリスナーが書き進めて、出力の着地と\n * source の新しい着地が同じバッチに載る連鎖では、出力を見る `$watch` の prev が前の着地を持ち、cur が\n * 1 段先行し、同じ値で 2 回発火し得る(D12 の契約・§5-6 の差し戻し)。\n *\n * 失敗は種類ごとに閉じる(D4): 読めない行はその行だけを捨てて連鎖を続け(`$watch` が行ごとに\n * evaluate で閉じるのと同じ)、出力の読み・fold の throw はその scan の書き込みを止める。\n */\n\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { getScopedIndexes } from \"../list/wildcardLevel\";\nimport type { IStateProxy } from \"../proxy/types\";\nimport { getStreamEntries } from \"../stream/streamRegistry\";\nimport { getUpdater } from \"../updater/updater\";\nimport { beginWatchFiring, endWatchFiring } from \"../watch/chainDepth\";\nimport { getPrevValue } from \"../watch/prevValues\";\nimport { selectLandedRows } from \"../watch/rowLanding\";\nimport { consumePendingScanReset, discardPendingScanResets } from \"./eventReset\";\nimport { cloneInitial, isSameAsInitial, recordOutputValue } from \"./initialValue\";\nimport { isThenable, reportLateGetterSource, reportScanError, reportScanThenable, type ScanFailure } from \"./scanReport\";\nimport { getScanDrainGateCount, getScanRegistry } from \"./scanRegistry\";\nimport type { IScanEntry, IScanPathSource } from \"./types\";\n\nexport interface IScanRow {\n readonly absAddress: IAbsoluteStateAddress;\n readonly indexes: number[];\n}\n\nexport interface IScanGroup {\n readonly stateElement: IStateElement;\n readonly entry: IScanEntry;\n readonly rows: IScanRow[];\n reset: boolean;\n}\n\n/** 相 1 の結果。`group.reset` なら相 2 が `initial` の複製を書く(出力が既に initial と同じ値なら書かない) */\nexport interface IScanPlan {\n readonly group: IScanGroup;\n readonly next: unknown;\n}\n\nconst NO_PLANS: readonly IScanPlan[] = Object.freeze([]);\n\nfunction groupOf(groups: Map<IScanEntry, IScanGroup>, stateElement: IStateElement, entry: IScanEntry): IScanGroup {\n let group = groups.get(entry);\n if (typeof group === \"undefined\") {\n group = { stateElement, entry, rows: [], reset: false };\n groups.set(entry, group);\n }\n return group;\n}\n\n/**\n * 同じ entry の行は wildcard の段数が同じ(indexes の長さが等しい)なので、\n * 外側の段から最初に違う段で比べる。\n */\nfunction compareRows(a: IScanRow, b: IScanRow): number {\n let level = 0;\n while (level < a.indexes.length - 1 && a.indexes[level] === b.indexes[level]) {\n level++;\n }\n return a.indexes[level] - b.indexes[level];\n}\n\n/**\n * `from` の根が `$streams` 名で、そのバッチにその stream の restart 依存が載っているか(D10)。\n * 載っていれば同じ drain の STREAM リスナーが run を abort する。到着した chunk は\n * 捨てられる run のものなので畳まない(`$streams` §3-2「restart が勝つ」)。\n */\nfunction isStreamRestartPending(\n stateElement: IStateElement,\n rootName: string,\n batch: ReadonlySet<IAbsoluteStateAddress>,\n): boolean {\n const streamEntry = getStreamEntries(stateElement).get(rootName);\n if (typeof streamEntry === \"undefined\") {\n return false;\n }\n for (const dep of streamEntry.depAddresses) {\n if (batch.has(dep)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasGetterOnPath(stateElement: IStateElement, source: IScanPathSource): boolean {\n for (const path of source.pathInfo.cumulativePaths) {\n if (stateElement.getterPaths.has(path)) {\n return true;\n }\n }\n return false;\n}\n\n/** 先行する fold や書き込みが同期に切断・再セットを起こし得る(`$watch` と同じ再確認) */\nfunction isLive(group: IScanGroup, activeStateElements: ReadonlySet<IStateElement>): boolean {\n return activeStateElements.has(group.stateElement)\n && getScanRegistry(group.stateElement)?.entries.has(group.entry) === true;\n}\n\n/**\n * 発火しないと決まった group の、`on` scan の保留 reset を捨てる(scan/eventReset.ts)。\n * `on` の group は `resetOn` のヒットからしか作られない。同じ `resetOn` のパスが次のバッチ向けに\n * 積まれていれば、その保留は次のバッチの drain が使うので残す(discardSkippedScanResets と同じ規則)。\n */\nfunction dropPendingReset(group: IScanGroup): void {\n const { entry, stateElement } = group;\n if (entry.source.kind === \"event\" && !entry.resetOn.some((path) => isQueuedForNextBatch(stateElement, path))) {\n consumePendingScanReset(entry);\n }\n}\n\n/** 次のバッチ(まだ drain されていない書き込み)に、この state のこのパスが積まれているか */\nfunction isQueuedForNextBatch(stateElement: IStateElement, path: string): boolean {\n return getUpdater().hasQueuedPath(stateElement, path);\n}\n\n/**\n * このバッチの scan を発火しない drain(発火対象でない state・連鎖深さの上限)で、`on` scan の\n * 保留 reset を捨てる。`firing` はこの drain で scan を発火する state の集合、null はバッチ全体を\n * 発火しない。同じ `resetOn` のパスが次のバッチ向けに積まれていれば、その保留は残す。\n */\nexport function discardSkippedScanResets(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n firing: ReadonlySet<IStateElement> | null,\n): void {\n discardPendingScanResets(batch, firing, isQueuedForNextBatch);\n}\n\nfunction readSource(state: IStateProxy, source: IScanPathSource, row: IScanRow): unknown {\n return source.pathInfo.wildcardCount === 0\n ? state[source.path]\n : state.$resolve(source.path, row.indexes);\n}\n\n/** 相 1: 次の値を読むだけで決める。書き込みは無いか null。 */\nfunction planGroup(\n group: IScanGroup,\n batch: ReadonlySet<IAbsoluteStateAddress>,\n activeStateElements: ReadonlySet<IStateElement>,\n): IScanPlan | null {\n if (!isLive(group, activeStateElements)) {\n dropPendingReset(group);\n return null;\n }\n const { stateElement, entry } = group;\n if (group.reset) {\n // reset が勝つ(D6)。同じバッチの行は畳まない\n return { group, next: entry.initial };\n }\n // reset でない group は `from` の行ヒットから作られている\n const source = entry.source as IScanPathSource;\n if (hasGetterOnPath(stateElement, source)) {\n reportLateGetterSource(entry, entry.name, source.path);\n return null;\n }\n if (isStreamRestartPending(stateElement, source.pathInfo.segments[0], batch)) {\n return null;\n }\n // コールバック内の代入は制御フロー解析に載らないので、結果と進み具合は入れ物で受け取る\n const result: { plan: IScanPlan | null; failure: ScanFailure } = { plan: null, failure: \"read-output\" };\n try {\n stateElement.createState(\"readonly\", (state) => {\n const start = state[entry.name];\n const rows = source.pathInfo.wildcardCount === 0\n ? group.rows\n : selectLandedRows(state, source.pathInfo, group.rows);\n result.failure = \"threw\";\n const fold = entry.fold;\n let acc = start;\n for (const row of rows.sort(compareRows)) {\n let cur: unknown;\n try {\n cur = readSource(state, source, row);\n } catch (error) {\n // 読めない行だけを捨てて、残りの行の連鎖は続ける\n reportScanError(entry.name, error, \"read-source\");\n continue;\n }\n const next = fold(acc, cur, getPrevValue(row.absAddress), ...row.indexes);\n if (isThenable(next)) {\n reportScanThenable(entry.name, next);\n return;\n }\n acc = next;\n }\n if (!Object.is(acc, start)) {\n result.plan = { group, next: acc };\n }\n });\n } catch (error) {\n // 他の scan・`$watch`・`$streams` restart を巻き添えにしない(D4)\n reportScanError(entry.name, error, result.failure);\n }\n return result.plan;\n}\n\n/** 相 2 の 1 件: 書く直前に再確認する(後続の scan の fold が同期に切断・再セットし得る)。 */\nfunction commitPlan(plan: IScanPlan, activeStateElements: ReadonlySet<IStateElement>): void {\n const { group } = plan;\n if (!isLive(group, activeStateElements)) {\n dropPendingReset(group);\n return;\n }\n const { stateElement, entry } = group;\n // `on` の reset は保留が残っているときだけ。書き込みの後に来た出来事が `initial` から\n // 畳んで保留を消していれば、その出力は reset 済み(scan/eventReset.ts)\n if (group.reset && entry.source.kind === \"event\" && !consumePendingScanReset(entry)) {\n return;\n }\n try {\n stateElement.createState(\"writable\", (state) => {\n const current = state[entry.name];\n // reset は既に initial と同じ値なら書かない(着地も `$watch` の発火も起こさない)。書くときは複製を置く(D6 / D7)\n const writes = group.reset ? !isSameAsInitial(current, entry.initial) : !Object.is(current, plan.next);\n if (writes) {\n const next = group.reset ? cloneInitial(entry.initial) : plan.next;\n state[entry.name] = next;\n recordOutputValue(entry.name, next);\n }\n });\n } catch (error) {\n reportScanError(entry.name, error, \"write\");\n }\n}\n\n/**\n * 相 1: バッチの `from` / `resetOn` ヒットを集め、宣言順に次の値を決める(書かない)。\n * `depth` は watch runtime が消費した連鎖深さ。fold の中の書き込みも連鎖に数える。\n */\nexport function planScansOnUpdateBatch(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n activeStateElements: ReadonlySet<IStateElement>,\n depth: number,\n): readonly IScanPlan[] {\n // 発火対象でない state(書き込みの後に切断された)の `on` scan の保留 reset を捨てる(D6)。\n // drain のゲートより前に置く — 切断で最後の scan がゲートから外れても、その書き込みの保留は残っている\n discardSkippedScanResets(batch, activeStateElements);\n if (getScanDrainGateCount() === 0) {\n return NO_PLANS;\n }\n const groups = new Map<IScanEntry, IScanGroup>();\n for (const absAddress of batch) {\n const stateElement = absAddress.absolutePathInfo.stateElement;\n if (!activeStateElements.has(stateElement)) {\n continue;\n }\n const registry = getScanRegistry(stateElement);\n if (typeof registry === \"undefined\") {\n continue;\n }\n const pathInfo = absAddress.absolutePathInfo.pathInfo;\n const fromEntries = registry.byFromPath.get(pathInfo.path);\n if (typeof fromEntries !== \"undefined\") {\n let indexes: number[] = [];\n if (pathInfo.wildcardCount > 0) {\n if (absAddress.listIndex === null) {\n // 行が特定できないヒット(リストの依存展開で載る中間アドレス等)。`$watch` と同じく落とす\n continue;\n }\n indexes = getScopedIndexes(absAddress.listIndex, pathInfo.wildcardCount);\n }\n for (const entry of fromEntries) {\n groupOf(groups, stateElement, entry).rows.push({ absAddress, indexes });\n }\n }\n const resetEntries = registry.byResetPath.get(pathInfo.path);\n if (typeof resetEntries !== \"undefined\") {\n for (const entry of resetEntries) {\n groupOf(groups, stateElement, entry).reset = true;\n }\n }\n }\n if (groups.size === 0) {\n return NO_PLANS;\n }\n const ordered = Array.from(groups.values()).sort((a, b) => a.entry.order - b.entry.order);\n const plans: IScanPlan[] = [];\n beginWatchFiring(depth);\n try {\n for (const group of ordered) {\n const plan = planGroup(group, batch, activeStateElements);\n if (plan !== null) {\n plans.push(plan);\n }\n }\n } finally {\n endWatchFiring();\n }\n return plans;\n}\n\n/**\n * 相 2: 計画を宣言順に書く(D18)。同じ drain の `$watch` の発火より前(D11)。\n * scan の書き込みも連鎖深さに数える。\n */\nexport function commitScanPlans(\n plans: readonly IScanPlan[],\n activeStateElements: ReadonlySet<IStateElement>,\n depth: number,\n): void {\n if (plans.length === 0) {\n return;\n }\n beginWatchFiring(depth);\n try {\n for (const plan of plans) {\n commitPlan(plan, activeStateElements);\n }\n } finally {\n endWatchFiring();\n }\n}\n","/**\n * watch/watchRuntime.ts\n *\n * `$watch` の発火(docs/state-watch-hook-design.md §3 / §7)。\n *\n * updater の drain 終了フックに 1 つだけリスナーを登録し、バッチに載った絶対アドレスと\n * 宣言済み watch パスを突き合わせて発火する。**binding の有無に関係なくバッチへ載る**ので、\n * これが headless 購読の実体になる(binding 駆動の `$updatedCallback` との違い)。\n *\n * 実行順序(設計書 §3-2):\n * - 機構間は優先度で固定(`$updatedCallback` → `$scan` → `$watch` → `$streams` restart)。\n * `$updatedCallback` が先なのは binding 適用ループの内側で呼ばれる構造的必然。\n * `$scan` の `from` / `resetOn` は同じリスナーの中で `$watch` より先に畳んで書く\n * (docs/state-scan-design.md D11 / D18)。\n * - watch ハンドラ間は `$watch` の宣言順(entry.order)。利用者が順序に意思を持てる唯一の層。\n * - 同一パスの複数行は indexes 昇順。\n *\n * 収集と発火を 2 相に分ける理由:\n * 1. ハンドラ内の書き込みが registry / active 集合を同期的に変えうる(`_state` 再 set・切断)\n * ため、発火直前に live 再チェックが要る(`$streams` の restart hits と同型)。\n * 2. 上記の順序規約のために hits をソートする必要がある(バッチの反復順は enqueue 順)。\n */\n\nimport { absoluteAddressOf } from \"../address/liftAddress\";\nimport type { IAbsoluteStateAddress } from \"../address/types\";\nimport type { IStateElement } from \"../components/types\";\nimport { MAX_WATCH_CHAIN_DEPTH, WATCH_LISTENER_PRIORITY } from \"../define\";\nimport { devtoolsSink } from \"../platform/devtoolsSink\";\nimport { getScopedIndexes } from \"../list/wildcardLevel\";\nimport type { IStateProxy } from \"../proxy/types\";\nimport { registerEnqueueListener, registerUpdateBatchListener } from \"../updater/updater\";\nimport { beginWatchFiring, consumeWatchChainDepth, endWatchFiring, noteEnqueueForWatchChain } from \"./chainDepth\";\nimport { getComputedSnapshot, setComputedSnapshot } from \"./computedSnapshots\";\nimport { clearPrevValues, getPrevValue } from \"./prevValues\";\nimport { IDeclarationHooks, registerDeclarationHooks } from \"../core/declarationHooks\";\nimport { STATE_SCAN_NAME, STATE_WATCH_NAME } from \"../define\";\nimport { inSsr } from \"../config\";\nimport { clearComputedSnapshots } from \"./computedSnapshots\";\nimport { processWatchDeclaration } from \"./processWatchDeclaration\";\nimport { clearWatchRegistry, deactivateWatch } from \"./watchRegistry\";\nimport { registerFeatureHooks } from \"../core/addressHooks\";\nimport { watchAddressHooks } from \"./addressHooks\";\nimport { hasRetiredRow, selectLandedRows } from \"./rowLanding\";\nimport { addActiveWatchStateElement, getActiveWatchStateElements, getVolumeWatchEntries, getWatchEntries } from \"./watchRegistry\";\nimport { hasScanDrainWork } from \"../scan/scanRegistry\";\nimport { commitScanPlans, discardSkippedScanResets, planScansOnUpdateBatch } from \"../scan/scanRuntime\";\nimport type { IWatchEntry } from \"./types\";\n\ninterface IWatchHit {\n readonly stateElement: IStateElement;\n readonly entry: IWatchEntry;\n readonly absAddress: IAbsoluteStateAddress;\n readonly indexes: number[];\n}\n\n/**\n * この stateElement の `$watch` を有効化する(`State.connectedCallback` /接続中の\n * `_state` 再 set から呼ばれる。無効化は `clearWatchRegistry`)。\n *\n * `addActiveWatchStateElement` の薄いラッパではなく、**State が runtime を import する\n * 経路をここに一本化する**意味がある: drain リスナーの登録はこのモジュールの\n * 初期化副作用なので、registry だけを import すると発火機構ごと落ちる。\n * `$streams` の `startStreams` と対称の位置づけ。\n *\n * **宣言が 1 つも無ければ active 集合に入れない**(`startStreams` の\n * `entries.size === 0` early return と同型)。ここを無条件にすると active 集合が\n * 「接続中の全 `<wcs-state>`」になり、`fireWatchOnUpdateBatch` の early return が\n * 実アプリで効かなくなる = `$watch` 未使用アプリの drain にも収集ループが乗る\n * (ゼロコスト契約、設計書 §10 / 実装計画 P16)。\n *\n * `$scan` の `from` / `resetOn` も同じ drain リスナーで発火するので、それだけを宣言した\n * state も発火対象に載せる(docs/state-scan-design.md D11)。\n */\nexport function startWatch(stateElement: IStateElement): void {\n // 初回の宣言起動で listener を確実に載せる(bootstrapState() を経ない経路の保険。冪等)\n installWatchRuntime();\n if (getWatchEntries(stateElement).size === 0 && getVolumeWatchEntries(stateElement).size === 0 && !hasScanDrainWork(stateElement)) {\n return;\n }\n addActiveWatchStateElement(stateElement);\n primeComputedWatches(stateElement);\n}\n\n/**\n * watch 対象の computed(getter)を 1 回評価する(設計書 §5-2 の eager 化、C-3)。\n *\n * これが要るのは、getter の依存(dynamicDependency)が**評価時にしか張られない**ため。\n * 一度も評価されていない getter は依存グラフに載らず、依存の書き込みが walkDependency で\n * そのパスへ到達しないので、バッチにも載らず watch が永久に発火しない。ここで 1 回\n * 読むことで依存が張られ、同時に `prev` の初期スナップショットが埋まる。\n *\n * **これが「watch した getter は lazy でなくなる」の実体**であり、設計書 §5-2 で\n * 規範として明記している副作用(毎バッチ評価・例外の表面化・依存の再登録)の起点。\n *\n * ワイルドカードを含む getter パス(`items.*.tax` など)は対象外: 初回評価に行ごとの\n * indexes が要り、全行評価は宣言しただけでリスト全体を舐めることになる。この形は\n * 「DOM にバインドされていれば発火する」ままとし、§5-3 に制約として書く。\n */\nfunction primeComputedWatches(stateElement: IStateElement): void {\n // 宣言(watch か scan)が 1 つ以上あることは startWatch が保証済み。scan だけなら targets は空\n const targets: IWatchEntry[] = [];\n for (const entry of getWatchEntries(stateElement).values()) {\n if (isScalarComputed(stateElement, entry)) {\n targets.push(entry);\n }\n }\n for (const entries of getVolumeWatchEntries(stateElement).values()) {\n for (const entry of entries) {\n if (isScalarComputed(stateElement, entry)) {\n targets.push(entry);\n }\n }\n }\n if (targets.length === 0) {\n // getter を watch していないなら createState ごと省く(宣言の大半はこちら)\n return;\n }\n stateElement.createState(\"readonly\", (state) => {\n for (const entry of targets) {\n try {\n // ワイルドカードを含まない watch パスなので、listIndex は常に null\n setComputedSnapshot(stateElement, absoluteAddressOf(stateElement, entry.pathInfo, null), state[entry.path]);\n } catch (e) {\n // 初回評価の throw は接続を巻き添えにしない(発火時と同じ隔離方針、§7-1)\n reportWatchError(stateElement, entry.path, \"prime\", e);\n }\n }\n });\n}\n\n\n/**\n * 前回評価値のスナップショット台帳(computedSnapshots)に載せる entry か。\n *\n * ワイルドカードを含む getter を**除く**のが要点。除かないと台帳のキーが行ごとの\n * 絶対アドレス(= listIndex を強参照)になり、prune 経路が `_state` 再 set しか\n * 無いため、行が入れ替わり続けるページで単調増加する(リスト置換 5 回で 2→10 件を実測)。\n * そもそもワイルドカード getter は eager 化の対象外(設計書 §5-3)なので、\n * 「初回評価もしない・前回値も持たない」で primeComputedWatches と対称になる。\n * この形の `prev` は常に undefined(getter は setByAddress を通らない)。\n */\nfunction isScalarComputed(stateElement: IStateElement, entry: IWatchEntry): boolean {\n return entry.pathInfo.wildcardCount === 0 && stateElement.getterPaths.has(entry.path);\n}\n\n/**\n * throw を報告する(設計書 §7-1)。\n *\n * `console.error` だけだと **devtools からは「静かに握られた失敗」が見えない**。\n * watch は drain フックを `$streams` と共有しており、例外を watch 側で閉じるのが\n * 前提なので、閉じた事実をここで観測可能にしておく必要がある。\n * イベント生成は必ず `devtoolsSink !== null` の内側で行う(sink のコスト規範)。\n */\nconst WATCH_ERROR_SUBJECT: Readonly<Record<\"prime\" | \"evaluate\" | \"handler\", string>> = {\n prime: \"initial evaluation of\",\n evaluate: \"evaluation of\",\n handler: \"handler for\",\n};\n\nfunction reportWatchError(\n stateElement: IStateElement,\n path: string,\n phase: \"prime\" | \"evaluate\" | \"handler\",\n error: unknown,\n): void {\n console.error(`[@wcstack/state] $watch ${WATCH_ERROR_SUBJECT[phase]} \"${path}\" threw.`, error);\n if (devtoolsSink !== null) {\n devtoolsSink({\n type: \"state:watch-error\",\n phase,\n path,\n error,\n });\n }\n}\n\nfunction fireWatchOnUpdateBatch(batch: ReadonlySet<IAbsoluteStateAddress>): void {\n const activeStateElements = getActiveWatchStateElements();\n try {\n if (activeStateElements.size === 0) {\n // watch 未使用アプリの drain に配列・イテレータ割り当てのコストを載せない。\n // ここも finally を通す: 宣言済みの state が切断されている間(active からは\n // 外れるが watchPaths は残る)の書き込みで台帳に旧値が積まれるため、\n // クリアを早期 return の外に置くと次のバッチどころか永久に残る。\n // 書き込みの後・drain の前に切断された state の `on` scan の保留 reset も、このバッチでは\n // 発火しないので捨てる(scan/eventReset.ts)。\n discardSkippedScanResets(batch, activeStateElements);\n return;\n }\n const depth = consumeWatchChainDepth();\n if (depth > MAX_WATCH_CHAIN_DEPTH) {\n // 打ち切るのは同じリスナーの発火(`$scan` の from / resetOn と `$watch`)のみ。\n // 値と binding 適用は巻き戻さない(伝播 hop 上限超過時の quarantine と同じ姿勢、§7-2)。\n // `on` scan の保留 reset もこのバッチでは効かせない(`from` の scan が reset しないのと揃える)。\n discardSkippedScanResets(batch, null);\n const paths = Array.from(batch, (absAddress) => absAddress.absolutePathInfo.pathInfo.path);\n console.error(\n `[@wcstack/state] $watch chain depth limit exceeded; $scan folds and $watch handlers for this batch were skipped.`,\n { maxDepth: MAX_WATCH_CHAIN_DEPTH, paths },\n );\n if (devtoolsSink !== null) {\n devtoolsSink({ type: \"state:watch-chain-limit\", maxDepth: MAX_WATCH_CHAIN_DEPTH, paths });\n }\n return;\n }\n\n // `$scan` の from / resetOn を `$watch` より先に畳んで書く(docs/state-scan-design.md D11 / D18)。\n // scan の書き込みは次のバッチに乗るので、この drain の `$watch` の収集には影響しない。同じ drain の\n // `$watch` ハンドラは書いた後の出力を読み、ハンドラが出力へ書いた値はそのまま残る。\n commitScanPlans(planScansOnUpdateBatch(batch, activeStateElements, depth), activeStateElements, depth);\n fireWatchHits(batch, activeStateElements, depth);\n } finally {\n // 旧値台帳はこの drain 限りのもの。次のバッチへ持ち越さない(§4-1)。\n clearPrevValues();\n }\n}\n\n/** バッチの `$watch` ヒットを集めて(収集フェーズ)、宣言順・indexes 昇順に発火する(発火フェーズ)。 */\nfunction fireWatchHits(\n batch: ReadonlySet<IAbsoluteStateAddress>,\n activeStateElements: ReadonlySet<IStateElement>,\n depth: number,\n): void {\n // --- 収集フェーズ ---\n const hits: IWatchHit[] = [];\n for (const absAddress of batch) {\n // stateElement 参照で引く。TreePath は\n // stateElement 単位でキャッシュされるので、同名 state が複数の rootNode に\n // 居ても取り違えない(address/TreePath.ts)。他 state のアドレスは\n // ここで自然に落ちる = 越境しない(設計 D8)。\n const stateElement = absAddress.absolutePathInfo.stateElement;\n if (!activeStateElements.has(stateElement)) {\n continue;\n }\n const path = absAddress.absolutePathInfo.pathInfo.path;\n const own = getWatchEntries(stateElement).get(path);\n const fromVolumes = getVolumeWatchEntries(stateElement).get(path);\n if (typeof own === \"undefined\" && typeof fromVolumes === \"undefined\") {\n continue;\n }\n const matched: IWatchEntry[] = typeof own === \"undefined\" ? [] : [own];\n if (typeof fromVolumes !== \"undefined\") {\n matched.push(...fromVolumes);\n }\n for (const entry of matched) {\n let indexes: number[] = [];\n if (entry.pathInfo.wildcardCount > 0) {\n if (absAddress.listIndex === null) {\n // ワイルドカードパスなのに行が特定できないヒット(リストの依存展開で載る\n // 中間アドレス等)。indexes を空のまま発火すると cur の解決($resolve)が\n // 「indexes 不足」で throw し、例外隔離に落ちて console.error だけが残る。\n // 行が定まらない以上ハンドラに渡せる意味が無いので、収集段階で落とす。\n continue;\n }\n indexes = getScopedIndexes(absAddress.listIndex, entry.pathInfo.wildcardCount);\n }\n hits.push({ stateElement, entry, absAddress, indexes });\n }\n }\n if (hits.length === 0) {\n return;\n }\n hits.sort(compareHits);\n const landed = selectWatchLandings(hits);\n\n // --- 発火フェーズ ---\n beginWatchFiring(depth);\n try {\n for (const hit of landed) {\n // 先行ハンドラが同期的に切断や `_state` 再 set を行い得るため、発火直前に\n // 「まだ active か」「entry が現行 registry のものか」を再確認する。\n if (!activeStateElements.has(hit.stateElement)) {\n continue;\n }\n const stillOwn = getWatchEntries(hit.stateElement).get(hit.entry.path) === hit.entry;\n const stillVolume = getVolumeWatchEntries(hit.stateElement).get(hit.entry.path)?.includes(hit.entry) === true;\n if (!stillOwn && !stillVolume) {\n continue;\n }\n fireOne(hit);\n }\n } finally {\n endWatchFiring();\n }\n}\n\n/**\n * ワイルドカードの watch の行の着地を、いまのリストの位置 1 つにつき 1 つに絞る(`$scan` の `from` と\n * 同じ選別 — watch/rowLanding.ts・#274)。`hits` は compareHits でソート済みで、戻り値もその順を保つ。\n *\n * 位置を引くにはリストを読むので、引くのは退役した行を含むヒットがあるか、同じ entry・同じ indexes の\n * ヒットが並ぶ(ソート済みなので隣り合う)entry だけ。行の値を書くだけのバッチ(大多数)は\n * WeakSet の引きだけで抜ける。\n */\nfunction selectWatchLandings(hits: IWatchHit[]): IWatchHit[] {\n let entries: Set<IWatchEntry> | null = null;\n for (let i = 0; i < hits.length; i++) {\n const hit = hits[i];\n if (hit.entry.pathInfo.wildcardCount === 0) {\n continue;\n }\n const previous = hits[i - 1];\n // ワイルドカードの hit は収集の段階で listIndex を持つものに限っている\n if (hasRetiredRow(hit.absAddress.listIndex!)\n || (previous?.entry === hit.entry && isSameIndexes(previous.indexes, hit.indexes))) {\n (entries ??= new Set()).add(hit.entry);\n }\n }\n if (entries === null) {\n return hits;\n }\n const dropped = new Set<IWatchHit>();\n for (const entry of entries) {\n // entry は 1 つの state 要素の registry に属するので、group の state 要素は 1 つ\n const group = hits.filter((hit) => hit.entry === entry);\n const stateElement = group[0].stateElement;\n try {\n stateElement.createState(\"readonly\", (state) => {\n const kept = new Set(selectLandedRows(state, entry.pathInfo, group));\n for (const hit of group) {\n if (!kept.has(hit)) {\n dropped.add(hit);\n }\n }\n });\n } catch (e) {\n // 位置を引く読み(リストのパスの getter など)が throw した。同じリストを通る cur も読めないので、\n // この entry のヒットは発火せず、評価の失敗として 1 回報告する(他の watch は続行する)\n reportWatchError(stateElement, entry.path, \"evaluate\", e);\n for (const hit of group) {\n dropped.add(hit);\n }\n }\n }\n return hits.filter((hit) => !dropped.has(hit));\n}\n\n/** 同じ entry の hit どうし(indexes の長さは等しい) */\nfunction isSameIndexes(a: readonly number[], b: readonly number[]): boolean {\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * 層 2(宣言順)→ 層 3(indexes 昇順)の順に比較する(設計書 §3-3)。\n */\nfunction compareHits(a: IWatchHit, b: IWatchHit): number {\n if (a.entry.order !== b.entry.order) {\n return a.entry.order - b.entry.order;\n }\n const length = Math.min(a.indexes.length, b.indexes.length);\n for (let i = 0; i < length; i++) {\n if (a.indexes[i] !== b.indexes[i]) {\n return a.indexes[i] - b.indexes[i];\n }\n }\n return a.indexes.length - b.indexes.length;\n}\n\n/**\n * ハンドラ 1 つを発火する。**例外はここで閉じる**(設計書 §7-1)。\n *\n * drain リスナーの throw は握りつぶさない契約(updater.ts)なので、watch 側で捕まえないと\n * 1 つのユーザー例外が他の watch と `$streams` の restart を巻き添えにする。\n * `$connectedCallback` / `$updatedCallback` の loud fail とは意図的に異なる扱い。\n *\n * 報告は throw 元で分ける: `cur` の解決(watch した getter の強制評価 = §5-2 の副作用 b)と\n * ハンドラ本体では原因も直し方も違うため、同じ文言に丸めない。\n */\nfunction fireOne(hit: IWatchHit): void {\n const { stateElement, entry, absAddress, indexes } = hit;\n // スカラ getter は setByAddress を通らないので旧値台帳に載らない。前回評価値の\n // スナップショット(バッチを跨いで生きる別台帳)から prev を取る(§5-2)。\n const isComputed = isScalarComputed(stateElement, entry);\n try {\n stateElement.createState(\"writable\", (state) => {\n let cur: unknown;\n try {\n // 強制評価はここ。dirty なら再計算され、その結果が cur になる\n cur = readCurrentValue(state, entry, indexes);\n } catch (e) {\n // cur が得られない以上ハンドラは呼べない。次の hit へ進む\n reportWatchError(stateElement, entry.path, \"evaluate\", e);\n return;\n }\n const prev = isComputed ? getComputedSnapshot(stateElement, absAddress) : getPrevValue(absAddress);\n if (isComputed) {\n // ハンドラ本体が throw しても次回の prev は「今回の評価値」であるべきなので、\n // handler 呼び出しより前に更新する\n setComputedSnapshot(stateElement, absAddress, cur);\n }\n // 正常発火の観測(設計書 §11 の予約イベント・配線カバレッジの実測面)。\n // 値は載せない。イベント生成は sink 接続時のみ(ゼロコスト契約)。\n // stateElement は発火元ツリーの識別(protocol v2 追補)— これが無いと\n // 複数ツリーが同名 watch パスを宣言するページで実測が合算される。\n if (devtoolsSink !== null) {\n devtoolsSink({ type: \"state:watch-fired\", path: entry.path, stateElement });\n }\n entry.handler.call(state, cur, prev, ...indexes);\n });\n } catch (e) {\n reportWatchError(stateElement, entry.path, \"handler\", e);\n }\n}\n\nfunction readCurrentValue(state: IStateProxy, entry: IWatchEntry, indexes: number[]): unknown {\n if (entry.pathInfo.wildcardCount === 0) {\n return state[entry.path];\n }\n // ワイルドカードを含むパスは素の読みでは解決できない。getScopedIndexes が返した列は\n // そのまま $resolve の引数として使える(list/wildcardLevel.ts の往復契約)。\n return state.$resolve(entry.path, indexes);\n}\n\n// drain 終了 listener の登録。優先度で `$streams` の restart より先に固定する(設計書 §3-2 層 1)。\n// モジュール評価時には登録しない: import しただけの利用(ヘルパーだけの import・分割エントリ)に\n// 副作用を残さないため、full / auto エントリの bootstrapState() が呼ぶ(冪等)。\nlet watchRuntimeInstalled = false;\nexport function installWatchRuntime(): void {\n if (watchRuntimeInstalled) return;\n watchRuntimeInstalled = true;\n registerFeatureHooks(\"watch\", watchAddressHooks);\n registerDeclarationHooks(\"watch\", watchDeclarationHooks);\n registerUpdateBatchListener(fireWatchOnUpdateBatch, WATCH_LISTENER_PRIORITY);\n // ハンドラ実行中の書き込みだけを連鎖としてマークする(chainDepth.ts)。ハンドラ実行中でなければ即 return\n registerEnqueueListener(noteEnqueueForWatchChain);\n}\n\n/**\n * `$watch` の宣言とライフサイクル(設計案 H4)。従来 `State` の `_state` セッターと\n * connectedCallback / disconnectedCallback に直書きされていた分岐で、順序の理由は各所に残した。\n */\nexport const watchDeclarationHooks: IDeclarationHooks = {\n // stream より先に起動し、後に停止する(受け口が deactivate を逆順で回す)\n order: 10,\n register(element, value) {\n // $watch: 旧宣言のハンドラが残らないよう registry を落としてから新宣言を解析する。\n // _pathSet.clear() の後であること(依存グラフ登録をやり直す必要がある、\n // docs/state-watch-hook-design.md §8)。宣言が無ければ watchPaths は null で、\n // setByAddress の旧値キャプチャには一切入らない(§10 のゼロコスト契約)。\n clearWatchRegistry(element);\n // computed の前回評価値も宣言と寿命を共にする(旧宣言の値を新しい watch の\n // prev として渡さない)。切断では消さない — 再接続の初回評価が上書きする。\n clearComputedSnapshots(element);\n const watchPaths = processWatchDeclaration(element, value);\n element.setWatchPaths?.(watchPaths);\n if (watchPaths !== null || element.scanPaths != null) {\n // 旧値の台帳(`$watch` の prev・`$scan` の from)は watch 機能の hook が書き込み時に記録する\n element.attachAddressHooks?.(\"watch\", watchPaths !== null ? STATE_WATCH_NAME : STATE_SCAN_NAME);\n }\n },\n activate(element, captured) {\n // SSR では走らせない — ハンドラの副作用がサーバとクライアントで二重に実行されるため\n // (docs/state-watch-hook-design.md §11)。rootNode ガード: $connectedCallback の await 中に\n // 切断された場合は起動しない。世代ガード(接続末尾のみ): await 中に「切断 → 即再接続」された\n // 場合、新 connect が rootNode を再設定済みでガードを素通りするため、世代不一致で陳腐化した\n // connect の再開を検出して skip する。\n // 再入不要: 接続中の再 set は下の宣言側で startWatch 済みだが、startWatch は Set への add で\n // 冪等なので $streams のような世代ガードは要らない。\n if (inSsr() || element.connectedRootNode == null) {\n return;\n }\n if (captured === null ? element.initialized !== true : captured !== element.connectGeneration) {\n return;\n }\n startWatch(element);\n },\n deactivate(element) {\n // watch は発火対象から外すだけで registry は保持する(stream の abortAllStreams と\n // 同じ二段構え、設計書 §9)。registry まで捨てると、_state セッターが再度走らない\n // 再接続で宣言を作り直せず watch が二度と発火しない。\n deactivateWatch(element);\n },\n};\n\nexport const __private__ = {\n fireWatchOnUpdateBatch,\n compareHits,\n};\n"],"names":["registryByStateElement","WeakMap","drainActive","Set","eventResetActive","hasDrainWork","registry","byFromPath","size","byResetPath","pushEntry","map","key","entry","list","get","set","push","setScanRegistry","stateElement","entries","clearScanRegistry","Map","eventResetByPath","source","kind","path","resetOn","getScanRegistry","deactivateScanGates","delete","pendingResets","WeakSet","pendingResetCount","eventResetEntriesAt","absAddress","absolutePathInfo","pathInfo","noteEnqueueForScanReset","has","markPendingScanReset","add","hasPendingScanReset","consumePendingScanReset","ARRAY_INDEX","isEnumerableData","target","descriptor","Object","getOwnPropertyDescriptor","enumerable","plainKind","value","isFrozen","proto","getPrototypeOf","Array","isArray","prototype","Reflect","ownKeys","every","test","cloneValue","copies","known","copy","length","create","keys","cloneInitial","initial","sameValue","current","compared","is","left","right","seen","index","hasOwnProperty","call","isSameAsInitial","outputNamesByFunction","recordOutputValue","name","names","wasPlacedOnOutput","SCAN_FAILURE_MESSAGE","STATE_SCAN_NAME","threw","write","SCAN_FAILURE_PHASE","sendToDevtools","phase","error","devtoolsSink","type","reportScanError","failure","console","isThenable","then","reportScanThenable","undefined","TypeError","lateGetterReported","UNCERTAIN","Symbol","lastNotifiedByStateElement","getLastNotified","status","setLastNotified","lastMap","pruneLastNotified","liveNames","invalidateLastNotified","last","activeStateElements","addActiveStateElement","deleteActiveStateElement","getActiveStateElements","setStreamEntries","getStreamEntries","abortAllStreams","values","controller","abort","clearStreamRegistry","firingDepth","pendingDepth","beginWatchFiring","depth","endWatchFiring","noteEnqueueForWatchChain","snapshotsByStateElement","setComputedSnapshot","snapshots","prevValueByAbsoluteStateAddress","recordPrevValue","oldValue","getPrevValue","volumeEntriesByStateElement","EMPTY_ENTRIES","getWatchEntries","addActiveWatchStateElement","hasEventResetWork","activateScanGates","getActiveWatchStateElements","addVolumeWatchEntries","byPath","EMPTY_VOLUME_ENTRIES","getVolumeWatchEntries","assertValidWatchPath","raiseError","STATE_WATCH_NAME","startsWith","LINT_HINT","includes","getPathInfo","segment","segments","wildcardCount","MAX_WILDCARD_DEPTH","processWatchDeclaration","state","declared","paths","order","handler","setPathInfo","setWatchEntries","watchAddressHooks","writeObserve","hasOldValue","watchPaths","scanPaths","swapped","_stateElement","elementAbsAddress","displacedAbsAddress","hasRetiredRow","listIndex","row","parentListIndex","isRetiredListIndex","placementOf","placement","level","getByAddressSymbol","createStateAddress","wildcardParentPathInfos","getListIndexesByList","indexes","own","listIndexAtWildcard","isSameListIndexValue","selectLandedRows","rows","byPosition","rank","join","kept","from","NO_PLANS","freeze","groupOf","groups","group","reset","compareRows","a","b","isLive","dropPendingReset","some","isQueuedForNextBatch","getUpdater","hasQueuedPath","discardSkippedScanResets","batch","firing","isQueued","discardPendingScanResets","readSource","$resolve","planGroup","next","cumulativePaths","getterPaths","hasGetterOnPath","message","Error","reportLateGetterSource","rootName","streamEntry","dep","depAddresses","isStreamRestartPending","result","plan","createState","start","fold","acc","sort","cur","commitPlan","planScansOnUpdateBatch","fromEntries","getScopedIndexes","resetEntries","ordered","plans","startWatch","installWatchRuntime","hasScanDrainWork","targets","isScalarComputed","absoluteAddressOf","e","reportWatchError","primeComputedWatches","WATCH_ERROR_SUBJECT","prime","evaluate","fireWatchOnUpdateBatch","consumeWatchChainDepth","MAX_WATCH_CHAIN_DEPTH","maxDepth","commitScanPlans","hits","fromVolumes","matched","compareHits","landed","i","hit","previous","isSameIndexes","dropped","filter","selectWatchLandings","stillOwn","stillVolume","fireOne","fireWatchHits","clear","Math","min","isComputed","readCurrentValue","prev","getComputedSnapshot","watchRuntimeInstalled","registerFeatureHooks","registerDeclarationHooks","watchDeclarationHooks","registerUpdateBatchListener","WATCH_LISTENER_PRIORITY","registerEnqueueListener","register","element","clearComputedSnapshots","setWatchPaths","attachAddressHooks","activate","captured","inSsr","connectedRootNode","initialized","connectGeneration","deactivate"],"mappings":"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"}