@wcstack/state 2.6.0 → 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 +97 -41
  2. package/README.md +99 -41
  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 -23342
  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,1417 @@
1
+ export { I as IStateFeature, i as installFeatures } from './chunks/features.js';
2
+
3
+ /**
4
+ * list/listKeys.ts
5
+ *
6
+ * `$listKeys: { <listPath>: <fieldName | (row) => key> }` 宣言マップを解析し、
7
+ * 「リストパス → キー指定」表を構築する(docs/state-list-key-design.md §3)。
8
+ *
9
+ * この表が存在するリストパスへの配列代入は、setByAddress でキー突合され、
10
+ * 一致行は旧オブジェクトを据え置いたまま変化フィールドだけが per-path 書き込みで
11
+ * 流し込まれる(§2)。未宣言なら書き込み経路は従来と完全に同一。
12
+ *
13
+ * 「そのパスが実際にリストか」は宣言時には判定できない(listPaths は
14
+ * バインディング収集時に確定する)。実行時に配列でなければ経路に入らないだけで、
15
+ * 宣言自体はエラーにしない。
16
+ */
17
+
18
+ /** キー指定: フラットなフィールド名、または行から複合キーを作る関数 */
19
+ type ListKeySpec = string | ((row: any) => unknown);
20
+ type ListKeyMap = ReadonlyMap<string, ListKeySpec>;
21
+
22
+ /**
23
+ * Interface for hierarchical loop index management in nested loops.
24
+ * Tracks parent-child relationships, versions, and provides access to index hierarchy.
25
+ */
26
+ interface IListIndex {
27
+ readonly parentListIndex: IListIndex | null;
28
+ readonly uuid: string;
29
+ readonly position: number;
30
+ readonly length: number;
31
+ index: number;
32
+ readonly version: number;
33
+ readonly dirty: boolean;
34
+ readonly indexes: number[];
35
+ readonly listIndexes: WeakRef<IListIndex>[];
36
+ readonly varName: string;
37
+ at(position: number): IListIndex | null;
38
+ }
39
+ interface ILoopContext extends IStateAddress {
40
+ readonly pathInfo: IPathInfo;
41
+ readonly listIndex: IListIndex;
42
+ }
43
+ interface ILoopContextStack {
44
+ createLoopContext(elementStateAddress: IStateAddress, callback: (loopContext: ILoopContext) => void | Promise<void>): void | Promise<void>;
45
+ }
46
+
47
+ declare const setLoopContextSymbol: unique symbol;
48
+ declare const getByAddressSymbol: unique symbol;
49
+ declare const hasByAddressSymbol: unique symbol;
50
+ declare const setByAddressSymbol: unique symbol;
51
+ declare const connectedCallbackSymbol: unique symbol;
52
+ declare const disconnectedCallbackSymbol: unique symbol;
53
+ declare const updatedCallbackSymbol: unique symbol;
54
+ declare const errorCallbackSymbol: unique symbol;
55
+
56
+ interface IStateHandler extends ProxyHandler<IState> {
57
+ readonly stateElement: IStateElement;
58
+ readonly addressStackLength: number;
59
+ /**
60
+ * アドレススタックの先頭(いま評価しているアドレス)。ループ文脈の無いスコープでは null。
61
+ * 再帰の深さ解決(recursion/bind.ts)もここだけを見る — 添字の供給元
62
+ * (getContextListIndex / `$getAll` の省略形)が先頭しか見ないので、深さだけを外側の
63
+ * フレームから拾うと「深さはあるが行が無い」定義にない状態になる。
64
+ */
65
+ readonly lastAddressStack: IStateAddress | null;
66
+ readonly loopContext: ILoopContext | null | undefined;
67
+ /**
68
+ * 依存追跡の抑止中か。$untrackDependency のスコープ内、および setter 実行中
69
+ * (setter は命令的な代入であって派生ではないため、その中の読み取りで依存を
70
+ * 張らない)は true。checkDependency / $1 インデックス依存の登録が抑止される。
71
+ */
72
+ readonly untracking: boolean;
73
+ /**
74
+ * このプロキシの書き込み能力。書き込み API の入口(proxy/assertWritable.ts)が検査する — set
75
+ * トラップを通らない `$resolve` / `$setAll` も readonly では書けない(要件 B6)。省略は writable。
76
+ */
77
+ readonly mutability?: Mutability;
78
+ pushAddress(address: IStateAddress | null): void;
79
+ popAddress(): IStateAddress | null;
80
+ setLoopContext(loopContext: ILoopContext | null): void;
81
+ clearLoopContext(): void;
82
+ beginUntrack(): void;
83
+ endUntrack(): void;
84
+ }
85
+ interface IStateProxy extends IState {
86
+ [setLoopContextSymbol](loopContext: ILoopContext | null, callback: () => any): any;
87
+ [getByAddressSymbol](address: IStateAddress): any;
88
+ [hasByAddressSymbol](address: IStateAddress): boolean;
89
+ [setByAddressSymbol](address: IStateAddress, value: any): void;
90
+ [connectedCallbackSymbol](): Promise<void>;
91
+ [disconnectedCallbackSymbol](): void;
92
+ [updatedCallbackSymbol](updatedAbsAddressList: IAbsoluteStateAddress[]): void;
93
+ [errorCallbackSymbol](error: unknown, info: IBindingErrorInfo): void;
94
+ }
95
+ type Mutability = "readonly" | "writable";
96
+
97
+ interface IContent {
98
+ readonly firstNode: Node | null;
99
+ readonly lastNode: Node | null;
100
+ readonly mounted: boolean;
101
+ appendTo(targetNode: Node): void;
102
+ mountAfter(targetNode: Node): void;
103
+ unmount(): void;
104
+ /**
105
+ * 自分のノードを DOM に残したままの解体(#4)。行の置き換えで `for` が同じ位置の Content を
106
+ * 新しい行に使い回すとき、入力中の欄を DOM から外さずに unmount と同じ後始末をする。
107
+ */
108
+ unmountInPlace(): void;
109
+ /**
110
+ * wholesale 破棄: 全行クリアで再利用されない content の binding teardown
111
+ * (listener 解除・アドレス台帳・loopContext 掃除)を省略し、ノード・binding
112
+ * もろとも GC に任せる。定義待ち等の副作用がある場合は false を返し、呼び出し側が
113
+ * 従来経路(deactivate + unmount)で解体する。
114
+ */
115
+ tryDestroy(): boolean;
116
+ }
117
+
118
+ /**
119
+ * core/addressHooks.ts — 読み書き境界の受け口(設計案 H1、S3)。
120
+ *
121
+ * 機能は `install()` でレジストリに hook 実装を置く(hot path には触れない)。state 要素は
122
+ * 宣言が要求する機能の hook だけを `attachAddressHooks` で自分に付け、core の各受け口は
123
+ * `stateElement.addressHooks` が null なら判定 1 回で抜ける
124
+ * (調査 §10.8: 大域配列の走査は読み +40%、state ごとの門なら +0.1 ns)。
125
+ * 宣言が要求する機能が未 install なら `requireFeature` が宣言時に throw する(readiness barrier、D13)。
126
+ *
127
+ * 受け口(core 側の呼び出し点):
128
+ * read getByAddress の先頭(キャッシュより前)。名前空間・マーカーなど raw state に無い値を答える
129
+ * readMissing getByAddress で「ツリーにそのキーが無い」と分かった点(親の値つき。親が無ければ null)
130
+ * write setByAddress の先頭。書き込みを奪うか、禁止して throw する
131
+ * writeMissing setByAddress の fast path で「親にそのキーが無い」と分かった点(公開 getter への書き込み)
132
+ * writeObserve 旧値が分かった点(同値ガードの直後)。旧値の台帳を持つ機能が読む
133
+ * written 書き込み・`$postUpdate` の後。観測面へ通知する機能が読む
134
+ * swapped 要素の入れ替えで行が動いた点(旧値の台帳を行に追従させる)
135
+ * get get トラップの文字列プロパティ先頭。API・名前空間・パスの翻訳を答える
136
+ * indexShift `$n` の解決点。スコープ相対の段ずれを足す
137
+ * handlerScope イベントハンドラの添字の段数を決める点
138
+ * updated `$updatedCallback` の後。相対配送する機能が読む
139
+ * suppressPathDiagnostic 束縛時の未宣言パス診断を黙らせるか(予約済みスロットの配下など)
140
+ * rowReused その場で使い回した行(DOM から外れない)の点。行の中のスコープを新しい listIndex へ張り直す
141
+ */
142
+
143
+ type ReadHook = (stateElement: IStateElement, address: IStateAddress, receiver: any, handler: IStateHandler) => unknown;
144
+ type ReadMissingHook = (stateElement: IStateElement, address: IStateAddress, parentValue: object | null, receiver: any, handler: IStateHandler) => unknown;
145
+ type WriteHook = (stateElement: IStateElement, address: IStateAddress, value: unknown, receiver: any, handler: IStateHandler) => unknown;
146
+ type WriteMissingHook = (stateElement: IStateElement, address: IStateAddress, parentValue: object, key: PropertyKey, value: unknown, receiver: any, handler: IStateHandler) => unknown;
147
+ type WriteObserveHook = (stateElement: IStateElement, path: string, absAddress: IAbsoluteStateAddress, oldValue: unknown, hasOldValue: boolean) => void;
148
+ type WrittenHook = (stateElement: IStateElement, pathInfo: IPathInfo, detail?: {
149
+ readonly value: unknown;
150
+ }) => void;
151
+ type SwappedHook = (stateElement: IStateElement, elementAbsAddress: IAbsoluteStateAddress, displacedAbsAddress: IAbsoluteStateAddress) => void;
152
+ type GetHook = (handler: IStateHandler, prop: string, receiver: any, target: object) => unknown;
153
+ type IndexShiftHook = (handler: IStateHandler, lastAddress: IStateAddress) => number;
154
+ type HandlerScopeHook = (stateElement: IStateElement, node: Node, rootNode: Node, loopContext: ILoopContext, wildcardCount: number) => number;
155
+ type UpdatedHook = (stateElement: IStateElement, refs: IAbsoluteStateAddress[], receiver: any) => void;
156
+ type SuppressPathDiagnosticHook = (stateElement: IStateElement, path: string) => boolean;
157
+ type RowReusedHook = (stateElement: IStateElement, content: IContent) => void;
158
+ interface IAddressHooks {
159
+ readonly read?: ReadHook;
160
+ readonly readMissing?: ReadMissingHook;
161
+ readonly write?: WriteHook;
162
+ readonly writeMissing?: WriteMissingHook;
163
+ readonly writeObserve?: WriteObserveHook;
164
+ readonly written?: WrittenHook;
165
+ readonly swapped?: SwappedHook;
166
+ readonly get?: GetHook;
167
+ readonly indexShift?: IndexShiftHook;
168
+ readonly handlerScope?: HandlerScopeHook;
169
+ readonly updated?: UpdatedHook;
170
+ readonly suppressPathDiagnostic?: SuppressPathDiagnosticHook;
171
+ readonly rowReused?: RowReusedHook;
172
+ }
173
+ /** state 要素に付いた hook 群(種類ごとに、機能の登録順) */
174
+ type IAttachedHooks = {
175
+ readonly [K in keyof Required<IAddressHooks>]: NonNullable<IAddressHooks[K]>[];
176
+ };
177
+
178
+ /**
179
+ * pathDiagnostics.ts — パスに関する**エラーの文言**(throw する側)と、診断の両面が共有する部品。
180
+ *
181
+ * 束縛時の存在検査(`user.nmae` のような打ち間違いを console.warn で知らせる開発時の診断)は
182
+ * `features/diagnostics` へ分けた(diagnostics/pathChecks.ts)。core に残るのは、実行を止める
183
+ * エラーの文言と、その did-you-mean が使う候補の集め方だけ。エラーは機能の有無に関わらず
184
+ * 読める文言で落ちなければならないので、ここは core から外せない。
185
+ *
186
+ * 診断 code はコンソール → lint → IDE の三面で共有する(errorGuidance.ts の規約)。
187
+ */
188
+ /** `setPathInfo` の呼び出し元の種別。診断 code と適用範囲がこれで変わる */
189
+ type PathInfoSource =
190
+ /** data-wcs / mustache / コメントバインディング */
191
+ "binding"
192
+ /** `$watch` の宣言キー */
193
+ | "watch"
194
+ /** `$scan` の `from` / `resetOn`(docs/state-scan-design.md §2-4) */
195
+ | "scan"
196
+ /** ランタイム内部のパス翻訳(mapped な bind-component の外向き伝播)。検査しない */
197
+ | "internal";
198
+
199
+ /**
200
+ * 単一の自己再帰宣言。初版はアンカーと反復サブパスとも「固定プロパティ列の末尾に
201
+ * `.*` がひとつ」の形に限定する(docs/state-recursive-path-impl-plan.md §1-1)。
202
+ *
203
+ * 例: `$recursion = { "nodes.*": "children.*" }`
204
+ * - `anchor` … `"nodes.*"`(深さ 0 のノードパス)
205
+ * - `repeat` … `"children.*"`(1 段深くする相対サブパス)
206
+ * - `recursiveAnchor` … `"nodes.**"`
207
+ * - `anchorList` … `"nodes"`
208
+ * - `repeatList` … `"children"`
209
+ *
210
+ * リスト側の 2 つは宣言時に確定させる(静的側の `RecursionSpec` と同じ構成)。
211
+ * 各所で `lastIndexOf(DELIMITER)` の slice を繰り返すと、綴りの取り違えが分散する。
212
+ */
213
+ interface IRecursionSpec {
214
+ readonly anchor: string;
215
+ readonly repeat: string;
216
+ /** `anchor` の `**` 形(`"nodes.**"`)。オーサリング層のパス解析で使う。 */
217
+ readonly recursiveAnchor: string;
218
+ /** `anchor` のリスト側(`"nodes"` — 末尾の `.*` を落とした形)。 */
219
+ readonly anchorList: string;
220
+ /** `repeat` のリスト側(`"children"`)。 */
221
+ readonly repeatList: string;
222
+ }
223
+ /**
224
+ * 展開済みの再帰 getter 1 本ぶんの素性。生成アクセサに紐づくメタデータで、
225
+ * ランタイムが読むのは深さ(`**` の束縛)と元の宣言(診断の名指し)の 2 つだけ。
226
+ * 具体パスは台帳のキー、`PathInfo` は読む側が intern 済みのものを持つので、ここには
227
+ * 重ねて持たない。
228
+ */
229
+ interface IRecursionAccessor {
230
+ /** 元の宣言(`"nodes.**.total"`) */
231
+ readonly recursivePath: string;
232
+ /** 反復の段数(0 origin) */
233
+ readonly depth: number;
234
+ }
235
+
236
+ /**
237
+ * recursion/registry.ts
238
+ *
239
+ * state 1 つぶんの再帰レジストリ。宣言・`**` getter の定義・展開済みアクセサの台帳を
240
+ * 持ち、「具体パスを読む直前に、その深さのアクセサを生やす」遅延実体化を担う。
241
+ *
242
+ * 遅延であることは実装の**不変条件**である(Phase A の A6/A7)。そのパスを一度でも
243
+ * 読んでから生やしても、`isCacheable` が `wildcardCount > 0` だけでキャッシュ可を返す
244
+ * ため `undefined` が `dirty:false` で固定され、以後どう書いても回復しない。
245
+ * したがって実体化は `getByAddress` のキャッシュ参照**前**に置く(E5)。
246
+ *
247
+ * 寿命は state の世代と共にする。`_state` の再セットで `getterPaths` / `listPaths` は
248
+ * クリアされるので、レジストリも作り直す(§1-3)。ただし**生やしたアクセサは state
249
+ * オブジェクトの側に残る**ので、同じ state を再セットすると `getStateInfo` がそれを
250
+ * `getterPaths` に復元する。そのとき「もう生えているから何もしない」と早期 return して
251
+ * しまうと `listPaths` の登録だけが抜け落ちるため、生成物は WeakSet で見分けて
252
+ * 登録だけをやり直す。
253
+ */
254
+
255
+ declare class RecursionRegistry {
256
+ readonly spec: IRecursionSpec;
257
+ private readonly _definitions;
258
+ private readonly _accessors;
259
+ /**
260
+ * `recursiveGetterOwning` の記憶。キーは添字を `*` に畳んだ形(`nodes.1.total` と `nodes.2.total`
261
+ * は 1 つ)、値は「その具体パスを展開形(またはその値の内側)として持つ `**` getter」、
262
+ * 無ければ null。
263
+ *
264
+ * 有界である: キーは添字を畳んだワイルドカード形のパス文字列で、`PathInfo` が intern する集合
265
+ * (バインディング・getter・API 引数に綴られたパスと、その展開形)の部分集合にしかならない。
266
+ * intern 済みパスの集合が有界であることは D10 で受け入れ済みなので、ここも同じ上限に収まる。
267
+ * 文字列は WeakSet に入らないので、寿命はレジストリ(= state の世代)と共にする。
268
+ */
269
+ private readonly _ownerByPath;
270
+ /**
271
+ * 書き込みのホットパス(`setByAddress`)向けの記憶。キーは intern 済みの `PathInfo` なので
272
+ * 寿命と上限は PathInfo の intern 集合と同じ(WeakMap)。畳み(split + Number + join)は
273
+ * miss のときだけ払う — 宣言のある state では**アンカー外を含む全書き込み**がここを通る
274
+ * (第 4 サイクルで実測: 畳みを毎回払うと `s.counter = i` で +100ns/書き込み)。
275
+ */
276
+ private readonly _ownerByPathInfo;
277
+ /**
278
+ * 読みのホットパス(`getByAddress`)向けの記憶。`_ownerByPathInfo` と対称で、キーは
279
+ * intern 済みの `PathInfo`、値は「そのパスの展開アクセサ」、展開形でなければ null。
280
+ * 宣言のある state では**アンカー外を含む全読み**(親ウォークの各段を含む)がここを
281
+ * 通るので、文字列キーの `Map.get` + `Set.has` + `startsWith` を毎回払わせない
282
+ * (第 5 サイクルで実測)。
283
+ *
284
+ * 読みの否定判定の記憶は**ここ 1 つ**(第 5 サイクル再検証で文字列キーの `_nonAccessors` を撤去 —
285
+ * 前段にこの記憶を置いた後は、PathInfo とパス文字列が 1:1 なので二重に持つだけだった)。
286
+ * 否定を記憶してよい根拠は、定義集合が state の世代内で不変であること —
287
+ * 同じ `PathInfo` は同じパス文字列なので、いちど「展開形でない」と決まった PathInfo が
288
+ * 後から実体化されることはない。実体化した側は `materializeForPathInfo` が
289
+ * `_define` の戻り値でそのまま記憶を更新する(否定が実体化を隠さない)。
290
+ */
291
+ private readonly _accessorByPathInfo;
292
+ /** `concretePathAt` の記憶(接尾辞 → 深さ順の具体パス)。 */
293
+ private readonly _concreteBySuffix;
294
+ private readonly _registeredListPaths;
295
+ constructor(spec: IRecursionSpec, state: object);
296
+ /**
297
+ * 作者が手で書いた具体パス(`get "nodes.*.children.*.total"()` / データプロパティ)が、宣言済み
298
+ * `**` getter の展開形と同名でないことを**構築時に**確かめる。
299
+ *
300
+ * `_define` の衝突検査は「その深さを最初に読んだとき」にしか走らないので、データが浅い間は
301
+ * 通り、木が 1 段深くなった瞬間にバインディングが落ちていた(第 3 サイクルのレビューで実測)。
302
+ * 前世代の生成物(own に残った生成 getter)は衝突ではない — 同じ state の再セットで必ず居る。
303
+ */
304
+ private _assertNoConcreteCollision;
305
+ /**
306
+ * 2 本の `**` getter が同じ具体パスへ展開しないことを、宣言だけから静的に確かめる。
307
+ *
308
+ * 衝突するのは「片方の接尾辞がもう片方の接尾辞の末尾で、差分が反復語の整数倍」の
309
+ * ときだけ(`nodes.**.total` と `nodes.**.children.*.total` は深さ k と k+1 で
310
+ * 同じ `nodes.*.children.*.total` になる)。検出しないと `_definitions` の挿入順で
311
+ * 最初に一致した方が無言で勝つ。
312
+ */
313
+ private _assertNoColliding;
314
+ /**
315
+ * `**` getter を 1 本でも宣言しているか。
316
+ * **テスト・診断専用**(ランタイムの経路は `_definitions.size` を直接見る)。
317
+ */
318
+ get hasDefinitions(): boolean;
319
+ /**
320
+ * その接尾辞が宣言済みの `**` getter と衝突するなら、その getter のパスを返す。
321
+ *
322
+ * 完全一致だけでは足りない。①反復語の整数倍だけ違う接尾辞は同じ族を指す
323
+ * (`_assertNoColliding` が宣言どうしについて既に見ている条件)②getter の**下**を
324
+ * 指す形(`nodes.**.total.x` / 反復語ぶんずれた `nodes.**.children.*.total.x`)は、
325
+ * getter が返したオブジェクトへ書いてキャッシュを汚し、次の無効化で無言に戻る。
326
+ * どちらも書き込みの入口(列挙より前)で止める — 述語は expand.ts の `coversSuffix`。
327
+ */
328
+ conflictingRecursiveGetter(suffix: string): string | null;
329
+ /**
330
+ * `recursiveGetterOwning` の intern 済み `PathInfo` 版(書き込みのホットパス用)。
331
+ * WeakMap の hit なら畳みも照合も払わない。
332
+ */
333
+ recursiveGetterOwningPath(pathInfo: IPathInfo): string | null;
334
+ /**
335
+ * 具体パスを展開形(またはその値の内側)として持つ `**` getter のパス。無ければ null。
336
+ * **実体化はしない。**
337
+ *
338
+ * `conflictingRecursiveGetter` の**具体パス版**で、`**` を経ない 2 つの入口が使う:
339
+ *
340
+ * - バインド確立時のパス存在検査(`checkDeclaredPath`)。あの時点ではまだ生えて
341
+ * いないので、素の存在検査では必ず「解決できない」になる。展開形そのもの
342
+ * (`nodes.*.total`)だけでなく、その値の中を指す形(`nodes.*.stats.count` で
343
+ * `get "nodes.**.stats"()` がオブジェクトを返す)も、通常の getter の下と同じく
344
+ * 評価しないと分からないので黙る側に倒す。
345
+ * - 書き込みの入口(`setByAddress`)。`$setAll("nodes.*.children.*.total", [], v)` や
346
+ * `this["nodes.1.total"] = v` は `**` を含まないので `setAllRecursive` の
347
+ * 読み取り専用検査を通らず、未実体化なら fast path が行オブジェクトへ素の
348
+ * プロパティとして書いてしまう(ノードを汚し、代入値が `dirty:false` で載って
349
+ * 以後 getter が評価されない)。展開形への書き込みは、実体化の前後に関わらず
350
+ * `wcs/recursion-readonly` で止める。
351
+ */
352
+ recursiveGetterOwning(concretePath: string): string | null;
353
+ /** 具体パスが宣言済み `**` getter の展開形そのものなら、その getter のパス。 */
354
+ private _matchExpansion;
355
+ /**
356
+ * `materializeFor` の `PathInfo` 版。**読みのホットパス(`getByAddress`)専用**で、
357
+ * 判定そのものは `materializeFor` に委ね、結果(否定を含む)を PathInfo に記憶する。
358
+ * 書き側の `recursiveGetterOwningPath` と対称。
359
+ */
360
+ materializeForPathInfo(stateElement: IStateElement, pathInfo: IPathInfo): IRecursionAccessor | null;
361
+ /**
362
+ * 具体パスが再帰 getter の展開形なら、そのアクセサを(未登録なら生やして)返す。
363
+ * 該当しなければ null。読みは `materializeForPathInfo` を通るので、ここへ来るのは
364
+ * 記憶が外れたときだけ — 判定は接頭辞 1 回で抜け、ここでは否定を記憶しない(記憶は
365
+ * `materializeForPathInfo` の PathInfo キーの 1 か所)。
366
+ * (`**` getter の無い空レジストリを弾くのは呼び出し側の役目。)
367
+ */
368
+ materializeFor(stateElement: IStateElement, concretePath: string): IRecursionAccessor | null;
369
+ private _define;
370
+ /**
371
+ * 経路上のリストパスを `listPaths` に載せる(E4)。`setPathInfo(path, "for")` は
372
+ * 使えない — あちらは `elementPaths` にも入れて `setByAddress` の swap 経路
373
+ * (`isSwappable`)を変えてしまう。ここで要るのは「依存ウォークがこのパスを
374
+ * リストとして展開する」ことだけ。
375
+ */
376
+ private _registerListPaths;
377
+ /**
378
+ * この世代が生やしたもの(own の生成アクセサ・依存辺・キャッシュ)を忘れる(state の
379
+ * 再セット時、`getStateInfo` の再収集より**前**に呼ぶ)。実体は generation.ts。
380
+ */
381
+ forgetGenerated(stateElement: IStateElement, previousState: object): ReadonlySet<string>;
382
+ /**
383
+ * `**` 接尾辞の深さ `depth` の具体パス(`concretePathAt` の記憶付き版)。
384
+ * 束縛形の読み(`this["nodes.**.value"]` / 省略形 `$getAll`)は再帰 getter の評価ごとに
385
+ * ここを通るので、深さぶんの文字列連結とワイルドカード数えを毎回やり直さない。
386
+ * 上限は「接尾辞の種類 × 128」で有界(上限超過は `concretePathAt` が throw するので載らない)。
387
+ */
388
+ concretePathAt(suffix: string, depth: number): string;
389
+ /** 展開済みアクセサのメタデータ(深さ解決・診断・テスト用)。 */
390
+ accessorFor(concretePath: string): IRecursionAccessor | null;
391
+ /**
392
+ * これまでに実体化した具体パスの一覧。**テスト専用**(「読んだ深さだけが生える」という
393
+ * 遅延実体化の不変条件を外から確かめる口。ランタイムはどの経路からも呼ばない)。
394
+ */
395
+ get materializedPaths(): ReadonlySet<string>;
396
+ }
397
+
398
+ interface IStateElement {
399
+ /** DOM connection state; optional for non-DOM state implementations. */
400
+ readonly isConnected?: boolean;
401
+ /**
402
+ * state のロードが完了しているか。`initializePromise` の同期版で、
403
+ * DCC のアクセサが「今すぐ読み書きしてよいか」を判断するのに使う。
404
+ * optional なのはテスト用モック互換のため(undefined は「不明=未初期化扱い」)。
405
+ */
406
+ readonly initialized?: boolean;
407
+ readonly initializePromise: Promise<void>;
408
+ readonly connectedCallbackPromise: Promise<void>;
409
+ readonly listPaths: Set<string>;
410
+ readonly elementPaths: Set<string>;
411
+ readonly getterPaths: Set<string>;
412
+ readonly setterPaths: Set<string>;
413
+ readonly loopContextStack: ILoopContextStack;
414
+ readonly dynamicDependency: Map<string, string[]>;
415
+ readonly staticDependency: Map<string, string[]>;
416
+ readonly version: number;
417
+ /**
418
+ * state の世代。`_state` の差し替えごとに 1 つ進み、キャッシュ項目の印になる
419
+ * (cache/types.ts の `generation`)。`version`(更新サイクルの番号)とは別のカウンタ。
420
+ * optional なのはテスト用モック互換のため(undefined のモックが載せた項目は
421
+ * undefined 同士で一致し、従来どおりヒットする — `__tests__/proxy.getByAddress.test.ts`
422
+ * の「キャッシュがある場合はキャッシュを返すこと」が固定する)。
423
+ */
424
+ readonly stateGeneration?: number;
425
+ readonly rootNode: Node;
426
+ readonly boundComponentStateProp: string | null;
427
+ /**
428
+ * `bind-component` で束ねられているコンポーネント要素(親スコープ側のノード)。
429
+ * マッピング規則の引き当てに使う。optional なのはテスト用モック互換のため。
430
+ */
431
+ /**
432
+ * この state の実体が innerState proxy(= 値の正本が親スコープの state にある
433
+ * mapped な `bind-component`)か。真のときだけ越境アドレスの受け渡しと
434
+ * リストパスの外向き伝播が働く(§1.8)。
435
+ * optional なのはテスト用モック互換のため(undefined は plain 扱い)。
436
+ */
437
+ /**
438
+ * この state element にマウント(Phase 2 の単一ツリー — webComponent/mount.ts)が
439
+ * 1 つでも登録されているか。偽のとき getByAddress / isCacheable / `$n` 補正は
440
+ * boolean 判定 1 個でオーバーレイ経路を抜ける(設計書 D18)。
441
+ * optional なのはテスト用モック互換のため(undefined は「マウント無し」扱い)。
442
+ */
443
+ readonly hasMounts?: boolean;
444
+ markHasMounts?(): void;
445
+ /**
446
+ * この state element に接ぎ木済みのボリューム(`mount=` — webComponent/volume.ts)が
447
+ * 1 つでもあるか。偽のとき setByAddress の D22 後段ガード(マウントポイントを含む
448
+ * 親の丸ごと書き検査)は boolean 判定 1 個で抜ける(設計書 D18 と同じ形)。
449
+ * optional なのはテスト用モック互換のため(undefined は「ボリューム無し」扱い)。
450
+ */
451
+ readonly hasGraftedVolumes?: boolean;
452
+ markHasGraftedVolumes?(): void;
453
+ /** ボリュームがこのルートに予約・接ぎ木された: スコープ機能の hook を付ける(webComponent/addressHooks.ts) */
454
+ markHasVolume?(): void;
455
+ /**
456
+ * ライフサイクル機能(core/lifecycleHooks.ts、設計案 H3)へ開く内部面。接続を引き取った機能が
457
+ * 要素の初期化を所有するために要る最小限で、optional はテスト用モック互換のため。
458
+ */
459
+ /** いま接続している rootNode(未接続は null)。公開の `rootNode` と違い throw しない */
460
+ readonly connectedRootNode?: Node | null;
461
+ clearConnectedRootNode?(): void;
462
+ /** 初期化完了の印(引き取った機能が自分の着地で立てる) */
463
+ markInitialized?(): void;
464
+ /** 初期化待ちの 3 つの promise を解決する(未解決のまま投げるとページが無言でウェッジする) */
465
+ settleInitialization?(): void;
466
+ /** `state` / `src` / 内包スクリプトからこの要素のソースを読む */
467
+ loadStateFromSource?(): Promise<Record<string, any>>;
468
+ /** 自分のツリーを持たずに初期化を終えた印(DCC 定義要素。再接続でこの rootNode のツリーとして登録し直さない) */
469
+ markTreeless?(): void;
470
+ /** 初期化失敗の着地(診断 1 件・connectedCallbackPromise の reject — #257)。常に throw する */
471
+ failInitializeLoudly?(error: unknown): never;
472
+ /** 接続の世代(接続の末尾の起動が、陳腐化した connect の再開を弾くために照合する) */
473
+ readonly connectGeneration?: number;
474
+ /** `$watch` / ボリュームの合流が決めた監視パス(setByAddress の旧値キャプチャのゲート) */
475
+ setWatchPaths?(paths: ReadonlySet<string> | null): void;
476
+ /** `$scan` の `from` パス(`watchPaths` と並ぶ旧値キャプチャのゲート) */
477
+ setScanPaths?(paths: ReadonlySet<string> | null): void;
478
+ /** 設定エラーの着地(初期化待ちの promise を解決し、二重着地の印を立てる) */
479
+ landInitialization?(): void;
480
+ /** `bind-component` が束ねた相手(`boundComponentStateProp` の答えになる) */
481
+ setBoundComponent?(component: Element | null, stateProp: string | null): void;
482
+ /** `$recursion` のレジストリ(宣言が無ければ null。`hasRecursion` の裏づけ) */
483
+ setRecursionRegistry?(registry: RecursionRegistry | null): void;
484
+ /** 前世代の再帰レジストリが生やした具体パス(経路情報の作り直しから除く) */
485
+ addGeneratedPath?(path: string): void;
486
+ /**
487
+ * 読み書き境界の hook(core/addressHooks.ts、設計案 H1)。宣言が要求する機能の分だけ
488
+ * `attachAddressHooks` で付く。無い state は null 判定 1 個で抜ける。optional はモック互換
489
+ */
490
+ readonly addressHooks?: IAttachedHooks | null;
491
+ attachAddressHooks?(feature: string, declaration: string): void;
492
+ /**
493
+ * この state 要素に束ねられた(`setPathInfo` を通った)パスの集合。丸ごとマウント
494
+ * (ルート規則)の親→子通知が「登録済みパス全部を読み直せ」を組み立てるのに使う
495
+ * (webComponent/rootReloadPaths.ts)。
496
+ * optional なのはテスト用モック互換のため(undefined は「登録なし」扱い)。
497
+ */
498
+ /**
499
+ * DCC の `$bindables` から生成した「パス → 変更イベント名」表。
500
+ * 唯一の書き手は defineDCC で、読み手は setByAddress。
501
+ * getter だけを公開して setter をインターフェースから落としていたため
502
+ * defineDCC が具象 State に依存していた(§3.5)。
503
+ */
504
+ readonly bindableEventMap: Record<string, string>;
505
+ setBindableEventMap(map: Record<string, string>): void;
506
+ readonly commandTokenNames: ReadonlySet<string>;
507
+ readonly eventTokenNames: ReadonlySet<string>;
508
+ /**
509
+ * state が $updatedCallback を定義しているか。false のとき drain は更新
510
+ * アドレスの集計と最終の writable createState を丸ごとスキップできる。
511
+ * optional なのはテスト用モック互換のため(undefined は「不明=集計する」)。
512
+ */
513
+ readonly hasUpdatedCallback?: boolean;
514
+ /**
515
+ * state が $errorCallback を定義しているか。true のとき drain は隔離したバインディング
516
+ * 適用失敗を console.error の代わりに $errorCallback へ配送する(devtools sink へは常に流す)。
517
+ * optional なのはテスト用モック互換のため(undefined は「未定義=console.error」)。
518
+ */
519
+ readonly hasErrorCallback?: boolean;
520
+ /**
521
+ * 他行を読む getter(隣接項目参照など)が検出されたリストパスの集合。
522
+ * これらのリストは walkDependency の diff-filter 展開の対象外(全行展開)。
523
+ * optional なのはテスト用モック互換のため(undefined は「検出なし」扱い)。
524
+ */
525
+ readonly crossRowListPaths?: ReadonlySet<string>;
526
+ addCrossRowListPath?(path: string): void;
527
+ /**
528
+ * 評価中に $1 等のインデックスを読んだ getter パスの集合(実行時検出)。
529
+ * 位置だけが変わった行(listDiff.changeIndexSet)は index 以外の入力が不変なので、
530
+ * walkDependency の静的子展開をこの集合の subtree に限定できる。
531
+ * optional なのはテスト用モック互換のため(undefined は「検出なし」扱い)。
532
+ */
533
+ readonly indexDependentGetterPaths?: ReadonlySet<string>;
534
+ addIndexDependentGetterPath?(path: string): void;
535
+ /**
536
+ * `$listKeys` 宣言から生成した「リストパス → キー指定」表。
537
+ * 宣言が無ければ null / undefined で、setByAddress のキー突合経路に一切入らない
538
+ * (docs/state-list-key-design.md §7-1 のゼロコスト契約)。
539
+ * optional なのはテスト用モック互換のため(undefined は「宣言なし」扱い)。
540
+ */
541
+ readonly listKeys?: ListKeyMap | null;
542
+ /**
543
+ * `$watch` 宣言から生成した監視対象パスの集合。
544
+ * 宣言が無ければ null / undefined で、setByAddress の旧値キャプチャには一切入らない
545
+ * (docs/state-watch-hook-design.md §10 のゼロコスト契約)。
546
+ * optional なのはテスト用モック互換のため(undefined は「宣言なし」扱い)。
547
+ */
548
+ readonly watchPaths?: ReadonlySet<string> | null;
549
+ /**
550
+ * `$scan` の `from` パスの集合(docs/state-scan-design.md §2-1)。`watchPaths` と並んで
551
+ * setByAddress の旧値キャプチャのゲートになる(fold に `prev` を渡すため)。
552
+ * 宣言が無ければ null / undefined。optional なのはテスト用モック互換のため。
553
+ */
554
+ readonly scanPaths?: ReadonlySet<string> | null;
555
+ /**
556
+ * パスを依存グラフへ登録する。DOM バインディング登録(BindingSession)のほか、
557
+ * `$watch` 宣言(processWatchDeclaration)からも呼ばれる — 静的依存グラフに
558
+ * 載るのがバインド済みパスだけだと headless 購読が成立しないため(設計書 §8)。
559
+ *
560
+ * `source` は存在検査の診断 code と適用範囲を決める(pathDiagnostics.ts)。
561
+ * 省略時は `"binding"`(テスト用モック互換のため optional)。
562
+ */
563
+ /** ボリュームの宣言面の合流(webComponent/volume.ts 専用・実装は State のみ) */
564
+ addVolumeWatchPaths?(paths: ReadonlySet<string>): void;
565
+ mergeVolumeListKeys?(entries: ReadonlyMap<string, ListKeySpec>): void;
566
+ enableUpdatedCallback?(): void;
567
+ /** enable-ssr スナップショットから初期化されたか(D14)。 */
568
+ readonly hydratedFromSsr?: boolean;
569
+ /** ボリュームのアクセサ登録(webComponent/volume.ts 専用) */
570
+ defineTreeAccessor(path: string, descriptor: PropertyDescriptor): void;
571
+ /**
572
+ * リストパスとしてだけ登録する(`listPaths` に足す)。`setPathInfo(path, "for")` は
573
+ * `elementPaths` にも入れて `setByAddress` の swap 経路(`isSwappable`)を変えるので、
574
+ * 「依存ウォークがこのパスをリストとして展開する」ことだけが要る用途には使えない
575
+ * (docs/state-recursive-path-impl-plan.md §3-2 の E4)。
576
+ */
577
+ addListPath(path: string): void;
578
+ /**
579
+ * state オブジェクト自身+プロトタイプチェーンから descriptor を引く(生成物と作者定義の
580
+ * 見分けに使う)。class 構文の getter は prototype に載るので own だけでは足りない。
581
+ */
582
+ findStateDescriptor(path: string): PropertyDescriptor | undefined;
583
+ /**
584
+ * この state に `$recursion` 宣言があるか。偽のとき getByAddress の遅延実体化と
585
+ * get トラップの `**` 解決は boolean 判定 1 個で抜ける(hasMounts と同じ D18 の形)。
586
+ * 読み手は必ずこのゲートを先に見て、真なら `recursionRegistry` を `!` で読む。
587
+ * 必須メンバー(実装は `State` のみ)。`any` 型のテスト用モックがフィールドを持たなくても
588
+ * 通るのは vitest が型検査をしないからで、その場合 `undefined === true` は偽なので再帰の
589
+ * 経路に入らないだけ — 型としては必須。
590
+ */
591
+ readonly hasRecursion: boolean;
592
+ /**
593
+ * 再帰レジストリ(宣言が無ければ null。`hasRecursion === true` なら非 null)。registry.ts は
594
+ * このファイルの IStateElement を参照するが、`import type` どうしなので実行時の循環にはならない。
595
+ */
596
+ readonly recursionRegistry: RecursionRegistry | null;
597
+ setPathInfo(path: string, bindingType: BindingType, source?: PathInfoSource): void;
598
+ addStaticDependency(parentPath: string, childPath: string): boolean;
599
+ addDynamicDependency(fromPath: string, toPath: string): boolean;
600
+ createStateAsync(mutability: Mutability, callback: (state: IStateProxy) => Promise<void>): Promise<void>;
601
+ createState(mutability: Mutability, callback: (state: IStateProxy) => void): void;
602
+ nextVersion(): number;
603
+ setInitialState(state: Record<string, any>): void;
604
+ }
605
+
606
+ interface IPathInfo {
607
+ readonly id: number;
608
+ readonly path: string;
609
+ readonly segments: string[];
610
+ readonly lastSegment: string;
611
+ readonly cumulativePaths: string[];
612
+ readonly cumulativePathSet: Set<string>;
613
+ readonly cumulativePathInfos: IPathInfo[];
614
+ readonly cumulativePathInfoSet: Set<IPathInfo>;
615
+ readonly parentPath: string | null;
616
+ readonly parentPathInfo: IPathInfo | null;
617
+ readonly wildcardPaths: string[];
618
+ readonly wildcardPathSet: Set<string>;
619
+ readonly indexByWildcardPath: Record<string, number>;
620
+ readonly wildcardPathInfos: IPathInfo[];
621
+ readonly wildcardPathInfoSet: Set<IPathInfo>;
622
+ readonly wildcardParentPaths: string[];
623
+ readonly wildcardParentPathSet: Set<string>;
624
+ readonly wildcardParentPathInfos: IPathInfo[];
625
+ readonly wildcardParentPathInfoSet: Set<IPathInfo>;
626
+ readonly wildcardPositions: number[];
627
+ readonly lastWildcardPath: string | null;
628
+ readonly lastWildcardInfo: IPathInfo | null;
629
+ readonly wildcardCount: number;
630
+ }
631
+ interface IStateAddress {
632
+ readonly pathInfo: IPathInfo;
633
+ readonly listIndex: IListIndex | null;
634
+ readonly parentAddress: IStateAddress | null;
635
+ }
636
+ interface ITreePath {
637
+ readonly stateElement: IStateElement;
638
+ readonly pathInfo: IPathInfo;
639
+ }
640
+ interface IAbsoluteStateAddress {
641
+ readonly absolutePathInfo: ITreePath;
642
+ readonly listIndex: IListIndex | null;
643
+ }
644
+
645
+ type BindingType = 'text' | 'prop' | 'event' | 'for' | 'if' | 'elseif' | 'else' | 'radio' | 'checkbox' | 'spread';
646
+
647
+ interface IState {
648
+ [key: string]: any;
649
+ }
650
+ interface ITagNames {
651
+ readonly state: string;
652
+ readonly ssr: string;
653
+ }
654
+ interface IWritableTagNames {
655
+ state?: string;
656
+ ssr?: string;
657
+ }
658
+ interface IConfig {
659
+ readonly bindAttributeName: string;
660
+ readonly commentTextPrefix: string;
661
+ readonly commentForPrefix: string;
662
+ readonly commentIfPrefix: string;
663
+ readonly commentElseIfPrefix: string;
664
+ readonly commentElsePrefix: string;
665
+ readonly tagNames: ITagNames;
666
+ readonly locale: string;
667
+ readonly debug: boolean;
668
+ readonly enableMustache: boolean;
669
+ /**
670
+ * Enables direction-aware initial synchronization (`init=` / `sync=`).
671
+ * Disabled by default while Phase 2 is evaluated against existing snapshots.
672
+ */
673
+ readonly enableDirectionalInitialSync: boolean;
674
+ /**
675
+ * Enables causal propagation tracking (transaction / edge provenance /
676
+ * write receipts). Disabled by default while Phase 3 runs as a shadow of
677
+ * the primitive same-value guard.
678
+ */
679
+ readonly enablePropagationContext: boolean;
680
+ /**
681
+ * Enables the opt-in dev-time contract analyzer (Phase 5b). When false
682
+ * (default), `analyzeContract()` is a no-op with zero cost — runtime
683
+ * behavior and allocation are unchanged. When true, it checks the actually
684
+ * loaded `static wcBindable` declarations against a supplied sidecar
685
+ * manifest and emits `contract:*` drift trace via the DevTools sink.
686
+ */
687
+ readonly enableContractAnalyzer: boolean;
688
+ /**
689
+ * 同値ガード(**既定 true**・標準的リアクティブ挙動・`setConfig({ sameValueGuard: false })` で opt-out 可)。
690
+ * primitive 値の set で `Object.is` 同値なら更新を no-op にする
691
+ * (enqueue / 依存 walk / DOM 適用 / $updatedCallback / DCC イベントを発火しない)。
692
+ * 参照型(object/array)は in-place mutation 取りこぼし防止のため素通し。
693
+ * 同値 set に副作用(同値時の $updatedCallback 等)を期待する場合は false にする。
694
+ */
695
+ readonly sameValueGuard: boolean;
696
+ }
697
+ /**
698
+ * `$errorCallback(error, info)` の第 2 引数 — 適用に失敗したバインディングの識別情報。
699
+ * 値と DOM は巻き戻されない(隔離規範)。作者はここで「どのバインディングが」を知り、
700
+ * 自分の state にエラーを書いてページ内で受ける。
701
+ */
702
+ interface IBindingErrorInfo {
703
+ /** バインドされた state パス(`data-wcs` に書かれた形。`items.*.name` などワイルドカードのまま) */
704
+ readonly path: string;
705
+ /** バインディング種別(text / property / attribute / class / style / for / if …) */
706
+ readonly bindingType: BindingType;
707
+ /** バインディングが付いたノード(テキストバインドでは Text ノード) */
708
+ readonly node: Node;
709
+ }
710
+ interface IWritableConfig {
711
+ bindAttributeName?: string;
712
+ commentTextPrefix?: string;
713
+ commentForPrefix?: string;
714
+ commentIfPrefix?: string;
715
+ commentElseIfPrefix?: string;
716
+ commentElsePrefix?: string;
717
+ tagNames?: IWritableTagNames;
718
+ locale?: string;
719
+ debug?: boolean;
720
+ enableMustache?: boolean;
721
+ enableDirectionalInitialSync?: boolean;
722
+ enablePropagationContext?: boolean;
723
+ enableContractAnalyzer?: boolean;
724
+ sameValueGuard?: boolean;
725
+ }
726
+
727
+ declare function bootstrapCore(config?: IWritableConfig, registry?: CustomElementRegistry): void;
728
+
729
+ declare function getConfig(): IConfig;
730
+
731
+ /**
732
+ * 指定された rootNode のバインディング初期化が完了するまで待機する Promise を返す。
733
+ */
734
+ declare function getBindingsReady(rootNode: Node): Promise<void>;
735
+
736
+ declare function buildBindings(root: Document | ShadowRoot): Promise<void>;
737
+
738
+ /**
739
+ * Trusted Types (`require-trusted-types-for 'script'`) 対応。正本は docs/csp.md §7。
740
+ *
741
+ * state が HTML sink に流すのは **状態の値**(`innerHTML: path` などのプロパティ
742
+ * バインド)で、ユーザー入力が混ざり得る文字列そのもの。ここに identity policy を
743
+ * 噛ませて通すのは TT の無効化と同義なので、state は自前の policy を作らない。
744
+ * 利用側が sanitizer を持つ policy を注入したときだけ通し、無ければ従来どおり
745
+ * ブラウザに弾かせる(ただし何を設定すれば直るかは必ず言う)。
746
+ *
747
+ * 注入口は全 @wcstack パッケージ共通のグローバルスロット。buildless(CDN 一発)でも
748
+ * inline script 1 本で差し込める:
749
+ *
750
+ * ```js
751
+ * globalThis[Symbol.for("wcstack.trustedTypes.policy")] =
752
+ * trustedTypes.createPolicy("my-app", { createHTML: (s) => DOMPurify.sanitize(s) });
753
+ * ```
754
+ *
755
+ * バンドラ経由なら `setTrustedTypesPolicy()` を使う。値は毎回スロットから読むので
756
+ * 後から差し替えても効く(identity policy を作る router / worker 側だけは
757
+ * `createPolicy` の重複を避けるため生成結果をシングルトンで保持する)。
758
+ */
759
+ interface IWcsTrustedTypesPolicy {
760
+ createHTML?(input: string): unknown;
761
+ createScriptURL?(input: string): unknown;
762
+ }
763
+ /** 利用側が policy を差し込むグローバルスロット(全 @wcstack パッケージ共通)。 */
764
+ declare const TRUSTED_TYPES_POLICY_SLOT: unique symbol;
765
+ /**
766
+ * 利用側が注入した policy を返す。state はここに identity policy をフォールバック
767
+ * させない(それをやると TT を無効化することになる)。
768
+ */
769
+ declare function getTrustedTypesPolicy(): IWcsTrustedTypesPolicy | null;
770
+ /** 利用側 policy を設定する(`null` で解除)。最初のバインド適用前に呼ぶこと。 */
771
+ declare function setTrustedTypesPolicy(policy: IWcsTrustedTypesPolicy | null): void;
772
+
773
+ /**
774
+ * defineState.ts
775
+ *
776
+ * 状態オブジェクトに型付けを提供するためのユーティリティ。
777
+ * defineState() はアイデンティティ関数で、ThisType<> を付与することで
778
+ * メソッド・computed getter 内の this に型補完を提供する。
779
+ *
780
+ * テンプレートリテラル型によるドットパスの型解決:
781
+ * - WcsPaths<T> : T から生成される全ドットパスの union
782
+ * - WcsPathValue<T,P>: パス P に対応する値の型
783
+ * - WcsPathAccessor<T>: ブラケットアクセス用マップ型
784
+ */
785
+ /**
786
+ * `any` 型を検出する。
787
+ * `0 extends (1 & T)` は T が `any` の場合のみ true になる。
788
+ */
789
+ type IsAny<T> = 0 extends (1 & T) ? true : false;
790
+ /**
791
+ * T がドットパス再帰の対象となる「プレーンなデータオブジェクト」かどうかを判定する。
792
+ * プリミティブ、組み込みオブジェクト (Date, Map 等)、関数、配列、any は除外。
793
+ */
794
+ type IsPlainObject<T> = IsAny<T> extends true ? false : T extends string | number | boolean | null | undefined | symbol | bigint | ((...args: any[]) => any) | Date | RegExp | Error | Map<any, any> | Set<any> | WeakMap<any, any> | WeakSet<any> | Promise<any> | readonly any[] ? false : T extends Record<string, any> ? true : false;
795
+ /**
796
+ * T のキーのうち、関数でないもの(データプロパティ・computed getter)を抽出する。
797
+ * メソッド(イベントハンドラ等)はドットパスの対象外。
798
+ * `$` プレフィックスキー($streams / $commandTokens / $on 等の予約宣言)もドットパスにならない。
799
+ * any 型のプロパティは除外せず保持する。
800
+ */
801
+ type DataKeys<T> = {
802
+ [K in keyof T & string]: K extends `$${string}` ? never : IsAny<T[K]> extends true ? K : T[K] extends (...args: any[]) => any ? never : K;
803
+ }[keyof T & string];
804
+ /**
805
+ * 型 T から生成される全てのドットパスの union。
806
+ * 配列プロパティはワイルドカード `*` を使用: `items.*.name`
807
+ *
808
+ * 再帰の深さは最大4レベルに制限(コンパイル性能の確保)。
809
+ *
810
+ * @example
811
+ * ```ts
812
+ * type S = {
813
+ * count: number;
814
+ * users: { name: string; age: number }[];
815
+ * cart: { items: { price: number }[] };
816
+ * };
817
+ * type P = WcsPaths<S>;
818
+ * // = "count" | "users" | "users.*" | "users.*.name" | "users.*.age"
819
+ * // | "cart" | "cart.items" | "cart.items.*" | "cart.items.*.price"
820
+ * ```
821
+ */
822
+ type WcsPaths<T, Depth extends readonly any[] = []> = Depth["length"] extends 4 ? never : {
823
+ [K in DataKeys<T>]: K | (T[K] extends readonly (infer E)[] ? IsPlainObject<E> extends true ? `${K}.*` | WcsSubPaths<E, `${K}.*.`, [...Depth, 0]> : `${K}.*` : IsPlainObject<T[K]> extends true ? WcsSubPaths<T[K], `${K}.`, [...Depth, 0]> : never);
824
+ }[DataKeys<T>];
825
+ /** @internal プレフィックス付きサブパスの生成ヘルパー */
826
+ type WcsSubPaths<T, Prefix extends string, Depth extends readonly any[]> = WcsPaths<T, Depth> extends infer P extends string ? `${Prefix}${P}` : never;
827
+ /**
828
+ * ドットパス P に対応する値の型を T から解決する。
829
+ *
830
+ * 解決順序:
831
+ * 1. T の直接キー(computed getter 含む)
832
+ * 2. `K.*` → 配列要素型
833
+ * 3. `K.rest` → オブジェクト/配列のネストを再帰的に辿る
834
+ *
835
+ * @example
836
+ * ```ts
837
+ * type S = { cart: { items: { price: number; qty: number }[] } };
838
+ * type V1 = WcsPathValue<S, "cart.items.*.price">; // number
839
+ * type V2 = WcsPathValue<S, "cart.items.*">; // { price: number; qty: number }
840
+ * type V3 = WcsPathValue<S, "cart">; // { items: ... }
841
+ * ```
842
+ */
843
+ type WcsPathValue<T, P extends string> = P extends keyof T ? T[P] : P extends `${infer K}.*` ? K extends keyof T ? T[K] extends readonly (infer E)[] ? E : never : never : P extends `${infer K}.${infer Rest}` ? K extends keyof T ? T[K] extends readonly (infer E)[] ? Rest extends `*.${infer SubRest}` ? WcsPathValue<E, SubRest> : Rest extends "*" ? E : never : T[K] extends Record<string, any> ? WcsPathValue<T[K], Rest> : never : never : never;
844
+ /**
845
+ * 全ドットパスに対する型付きブラケットアクセスを提供するマップ型。
846
+ *
847
+ * `this["users.*.name"]` のようなアクセスに対して、
848
+ * WcsPaths で生成されたパスに対応する値の型を返す。
849
+ */
850
+ type WcsPathAccessor<T> = {
851
+ [P in WcsPaths<T>]: WcsPathValue<T, P>;
852
+ };
853
+ /**
854
+ * `<wcs-state>` の Proxy 経由で提供されるAPIメソッド。
855
+ * state定義オブジェクト内のメソッド・getter で `this.` 経由で利用可能。
856
+ */
857
+ interface WcsStateApi {
858
+ /**
859
+ * ワイルドカードを含むパスにマッチする全要素を配列で取得する。
860
+ *
861
+ * @param path - ワイルドカードを含むパス
862
+ * @param indexes - 各ワイルドカード階層のインデックス(前方一致の接頭辞。`[]` は全階層を展開)。
863
+ * 省略時はループ文脈の添字(`[$1..$n]` 相当)のうち path と共有するワイルドカード連鎖の
864
+ * 分が接頭辞として敷かれる(文脈が path より深い分は切り詰め)。共有が無いのに文脈が
865
+ * 添字を持つ場合は throw する — 異なる文脈の添字は流用しない。
866
+ *
867
+ * @example
868
+ * ```ts
869
+ * get "cart.totalPrice"() {
870
+ * return this.$getAll("cart.items.*.price").reduce((sum, v) => sum + v, 0);
871
+ * }
872
+ * ```
873
+ */
874
+ $getAll<V = any>(path: string, indexes?: number[]): V[];
875
+ /**
876
+ * ワイルドカードを含むパスにマッチする**全アドレスへ一括で書き込む**(`$getAll` の対称形)。
877
+ *
878
+ * 配列を作り直さずに一括更新するための API。`this.users = this.users.map(...)` は
879
+ * ListIndex・行 getter キャッシュ・差分描画をまとめて作り直すが、`$setAll` は
880
+ * in-place な個別書き込みに分解するのでリストの同一性が保たれる。
881
+ *
882
+ * - `indexes` は `$getAll` と同じ**前方一致の接頭辞**(`[]` で全階層を展開)。省略は不可。
883
+ * - 関数を渡すと **mapper**(`(current, ...indexes) => next`)として要素ごとに評価される。
884
+ * - 配列は既定でブロードキャストされる。1 件ずつ配るには `{ spread: true }` を明示する。
885
+ * - `undefined` を書こうとした要素はスキップされる(クリアは `null`)。
886
+ *
887
+ * @returns 実際に書き込んだ件数(`undefined` でスキップした分を含まない)
888
+ *
889
+ * @example
890
+ * ```ts
891
+ * toggleAll(e: Event) {
892
+ * this.$setAll("users.*.selected", [], (e.target as HTMLInputElement).checked);
893
+ * }
894
+ * invertAll() {
895
+ * this.$setAll("users.*.selected", [], cur => !cur);
896
+ * }
897
+ * ```
898
+ */
899
+ $setAll<V = any>(path: string, indexes: number[], value: V | ((current: V, ...indexes: number[]) => V | undefined)): number;
900
+ $setAll<V = any>(path: string, indexes: number[], values: readonly V[], options: {
901
+ spread: true;
902
+ }): number;
903
+ /**
904
+ * 指定パスの更新を手動でトリガーする。
905
+ * Proxy の set トラップを経由せずに内部状態を変更した場合に使用。
906
+ */
907
+ $postUpdate(path: string): void;
908
+ /**
909
+ * パスとインデックス配列を指定して、ワイルドカードを解決した値を取得・設定する。
910
+ *
911
+ * @param path - ワイルドカードを含むパス
912
+ * @param indexes - 各ワイルドカード階層のインデックス
913
+ * @param value - 設定する値(省略時は取得)
914
+ */
915
+ $resolve(path: string, indexes: number[], value?: any): any;
916
+ /**
917
+ * 指定パスへの依存関係を明示的に登録する。
918
+ * computed getter 内で動的にパスを組み立てる場合に使用。
919
+ */
920
+ $trackDependency(path: string): void;
921
+ /**
922
+ * コールバック実行中の依存追跡(動的依存・`$1` インデックス依存の登録)を
923
+ * 抑止して fn を実行し、その戻り値を返す(`$trackDependency` と対称)。
924
+ * リスト行 getter が「行外の単一値」を読みたいが、その値の変更で全行を
925
+ * 再評価させたくない場合に使う(該当行へ直接書き込む設計と組で用いる)。
926
+ */
927
+ $untrackDependency<T>(fn: () => T): T;
928
+ /**
929
+ * 鍵付き購読: `path` の現在値が `key` に等しいかを返し、評価中のリスト行 getter を
930
+ * その鍵で購読する。`path` への書き込みは旧値・新値の鍵の行だけを再評価する
931
+ * (パターン依存なら全行)。`path` 自体は依存として追跡しない。
932
+ * 例: `get "items.*.selected"() { return this.$eq("selectedId", this.$untrackDependency(() => this["items.*.id"])); }`
933
+ */
934
+ $eq(path: string, key: unknown): boolean;
935
+ /**
936
+ * `$eq` の鍵を `keyPath`(ワイルドカードは評価中の行で解決)から依存を張らずに読む形。
937
+ * 例: `get "items.*.selected"() { return this.$eqPath("selectedId", "items.*.id"); }`
938
+ */
939
+ $eqPath(path: string, keyPath: string): boolean;
940
+ /**
941
+ * `$eq` の鍵を評価中の行の index(`$1` 相当。`level` でワイルドカード段を選ぶ)にする形。
942
+ * getter を index 依存には記録せず、行の移動時はリスト差分が鍵を付け替えるので、
943
+ * 1 行削除で再評価されるのは高々 2 行。
944
+ * 例: `get "items.*.selected"() { return this.$eqIndex("selectedIndex"); }`
945
+ */
946
+ $eqIndex(path: string, level?: number): boolean;
947
+ /** `<wcs-state>` 要素への参照 */
948
+ readonly $stateElement: HTMLElement;
949
+ /**
950
+ * `$commandTokens` で宣言した command token の名前空間。
951
+ * `this.$command.<name>` で token を解決できる(バインディングでは
952
+ * `onclick: $command.<name>` / `command.<method>: $command.<name>`)。
953
+ */
954
+ readonly $command: Record<string, {
955
+ emit(...args: any[]): any;
956
+ }>;
957
+ /** `$streams` 各エントリの状態("idle" | "active" | "done" | "error")を返す読み取り専用名前空間 */
958
+ readonly $streamStatus: Record<string, "idle" | "active" | "done" | "error">;
959
+ /** `$streams` 各エントリの直近エラーを返す読み取り専用名前空間 */
960
+ readonly $streamError: Record<string, unknown>;
961
+ readonly [key: `$streamStatus.${string}`]: "idle" | "active" | "done" | "error";
962
+ readonly [key: `$streamError.${string}`]: unknown;
963
+ readonly $1: number;
964
+ readonly $2: number;
965
+ readonly $3: number;
966
+ readonly $4: number;
967
+ readonly $5: number;
968
+ readonly $6: number;
969
+ readonly $7: number;
970
+ readonly $8: number;
971
+ readonly $9: number;
972
+ readonly [key: `${string}.**.${string}`]: any;
973
+ readonly [key: `${string}.**`]: any;
974
+ }
975
+ /**
976
+ * state定義オブジェクト内の `this` の型。
977
+ *
978
+ * - `T` のプロパティに型付きでアクセス可能(直接キー)
979
+ * - `WcsPathAccessor<T>` によるネストされたドットパスの型付きアクセス
980
+ * - `WcsStateApi` のメソッド ($getAll, $postUpdate 等) にアクセス可能
981
+ * - 動的パス (`this[\`items.${i}.name\`]`) は型チェック対象外(キャストが必要)
982
+ *
983
+ * @example
984
+ * ```ts
985
+ * defineState({
986
+ * count: 0,
987
+ * users: [] as { name: string; age: number }[],
988
+ * increment() {
989
+ * this.count++; // number
990
+ * this["users.*.name"]; // string (パス型解決)
991
+ * this.$getAll("users.*.age"); // API
992
+ * }
993
+ * });
994
+ * ```
995
+ */
996
+ type WcsThis<T> = T & WcsStateApi & WcsPathAccessor<T>;
997
+ /**
998
+ * `<wcs-state>` 用の型付き状態オブジェクトを定義する。
999
+ *
1000
+ * ランタイムではアイデンティティ関数(引数をそのまま返す)として動作し、
1001
+ * コストはゼロ。TypeScript の `ThisType<>` を利用して、メソッド・getter 内の
1002
+ * `this` に型補完を提供する。
1003
+ *
1004
+ * ### 基本的な使い方 (TypeScript)
1005
+ * ```ts
1006
+ * import { defineState } from '@wcstack/state';
1007
+ *
1008
+ * export default defineState({
1009
+ * count: 0,
1010
+ * users: [] as { name: string; age: number }[],
1011
+ *
1012
+ * increment() {
1013
+ * this.count++; // ✅ number
1014
+ * this["users.*.name"]; // ✅ string (ドットパス型解決)
1015
+ * },
1016
+ *
1017
+ * get "users.*.ageCategory"() {
1018
+ * return this["users.*.age"] < 25 ? "Young" : "Adult";
1019
+ * }
1020
+ * });
1021
+ * ```
1022
+ *
1023
+ * ### JavaScript (JSDoc)
1024
+ * ```js
1025
+ * import { defineState } from '@wcstack/state';
1026
+ *
1027
+ * export default defineState({
1028
+ * count: 0,
1029
+ * increment() {
1030
+ * this.count++; // ✅ JSDoc + tsconfig checkJs で型補完
1031
+ * }
1032
+ * });
1033
+ * ```
1034
+ *
1035
+ * ### HTML インラインスクリプト
1036
+ * ```html
1037
+ * <wcs-state>
1038
+ * <script type="module">
1039
+ * import { defineState } from '@wcstack/state';
1040
+ * export default defineState({
1041
+ * count: 0,
1042
+ * increment() { this.count++; }
1043
+ * });
1044
+ * </script>
1045
+ * </wcs-state>
1046
+ * ```
1047
+ *
1048
+ * ### ライフサイクルコールバック
1049
+ * ```ts
1050
+ * export default defineState({
1051
+ * data: null,
1052
+ * async $connectedCallback() {
1053
+ * this.data = await fetch('/api/data').then(r => r.json());
1054
+ * },
1055
+ * $disconnectedCallback() {
1056
+ * // cleanup
1057
+ * },
1058
+ * $updatedCallback() {
1059
+ * // called after DOM update
1060
+ * }
1061
+ * });
1062
+ * ```
1063
+ */
1064
+ declare function defineState<T extends Record<string, any>>(definition: T & ThisType<WcsThis<T>>): T;
1065
+
1066
+ declare const VERSION: string;
1067
+
1068
+ /**
1069
+ * Browser builds use the native HTMLElement. Headless runtimes receive an
1070
+ * inert base so the public module can be imported without installing DOM
1071
+ * globals; constructing components remains a browser-only operation.
1072
+ */
1073
+ declare const HTMLElementBase: typeof HTMLElement;
1074
+
1075
+ declare class State extends HTMLElementBase implements IStateElement {
1076
+ static hasConnectedCallbackPromise: boolean;
1077
+ static getBindingsReady(rootNode: Node): Promise<void>;
1078
+ /**
1079
+ * `mount` の動的変更は未サポート(再マウントは非目標 — 設計書 §4-7)。
1080
+ * 初期化済み要素での変更は無言で捨てず warn で知らせる。初期化前の属性設定
1081
+ * (パース時・接続前の setAttribute)は正規の使い方なので黙る。
1082
+ * `name` は connectedCallback 冒頭で fail-fast 済みなので観測しない。
1083
+ */
1084
+ static get observedAttributes(): string[];
1085
+ private __state;
1086
+ private _hasUpdatedCallback;
1087
+ /** $errorCallback の有無(_hasUpdatedCallback と同じく state セット時に確定。ルートのみ) */
1088
+ private _hasErrorCallback;
1089
+ /** enable-ssr のスナップショットから初期化された(D14: ボリュームはデータを採用する) */
1090
+ private _hydratedFromSsr;
1091
+ private _crossRowListPaths;
1092
+ private _indexDependentGetterPaths;
1093
+ private _initialized;
1094
+ /**
1095
+ * 初期化(`_initialize`)が失敗した(#257)。`_initialized` の裏返しではない —
1096
+ * 「まだ初期化していない」と「もう初期化できない」を取り違えると、復旧不能の
1097
+ * 要素に `setInitialState` が効いたように見える。真にするのは
1098
+ * `_failInitializeLoudly` だけ。
1099
+ */
1100
+ private _initializeFailed;
1101
+ /**
1102
+ * この接続サイクルの失敗は**もう着地した**(#257)。設定エラーの fail-fast
1103
+ * (`_failInitialization` と `initializeMountScope` の catch)は自分で promise を
1104
+ * 解決してから raise する — connectedCallbackPromise を**解決**する側のクラスなので、
1105
+ * 下の loud な着地(reject + 診断)に載せ替えると意味論が変わる。接続ごとに畳む。
1106
+ */
1107
+ private _initializationLanded;
1108
+ private _initializePromise;
1109
+ private _resolveInitialize;
1110
+ private _connectedCallbackPromise;
1111
+ private _resolveConnectedCallback;
1112
+ private _rejectConnectedCallback;
1113
+ private _loadingPromise;
1114
+ private _resolveLoading;
1115
+ private _setStatePromise;
1116
+ private _resolveSetState;
1117
+ private _listPaths;
1118
+ private _listKeys;
1119
+ private _recursionRegistry;
1120
+ private _elementPaths;
1121
+ private _getterPaths;
1122
+ private _setterPaths;
1123
+ private _loopContextStack;
1124
+ private _dynamicDependency;
1125
+ private _staticDependency;
1126
+ private _pathSet;
1127
+ /**
1128
+ * state の世代(issue #258 の X10)。`_state` の差し替えごとに 1 つ進み、キャッシュ項目の
1129
+ * 印になる(cache/types.ts の `generation`)。`_version`(更新サイクルの番号)とは別の
1130
+ * カウンタで、増える条件が違う — 再セットは世代だけを進める
1131
+ * (`__tests__/integration.stateGenerationReset.test.ts` の
1132
+ * 「再セットは世代だけを進め、version は動かさない」が固定する)。
1133
+ */
1134
+ private _stateGeneration;
1135
+ /**
1136
+ * この要素が受け取った `setPathInfo` の台帳(issue #258 の X7)。パス → 種別と呼び出し元。
1137
+ *
1138
+ * `_pathSet` / `_listPaths` / `_elementPaths` は再セットでクリアされるが、それらを登録した
1139
+ * バインドは生き残る(再セットは DOM を作り直さない)。台帳が空のままだと依存ウォークが
1140
+ * `items` をリストとして展開できず、全リスト書き込みが「非リストのアドレスにワイルドカードを
1141
+ * 展開できない」で恒久的に throw する(値と DOM は追従するが、書き込みのたびに投げ続ける)。
1142
+ * クリアのあと、この台帳から作り直す(`_rebuildPathInfo`)。
1143
+ *
1144
+ * `source === "internal"`(再帰の生成アクセサ・ボリュームのツリーアクセサ)は載せない。
1145
+ * あれらは生やした機構が新しい世代で登録し直す(recursion/registry.ts の `_define`)。
1146
+ *
1147
+ * `bound` はバインドがいちどでも登録したか(#270)。作り直しで存在検査をやり直すのはバインドの
1148
+ * パスだけ — `$watch` / `$scan` の登録は前の世代の宣言の残骸でもあり、今の世代の宣言は
1149
+ * 作り直しの後で自分の検査をする(`processWatchDeclaration` / `registerScans`)。残骸まで
1150
+ * 検査すると、新しい宣言から外したパスを「存在しない」と誤って報告する。
1151
+ */
1152
+ private _pathRegistrations;
1153
+ /**
1154
+ * 切断中の再セットで適用し直せなかったトップレベルのパス(#267)。再適用には rootNode が要るので、
1155
+ * 再接続で `reapplyStateBindings` に渡す。切断中に何度入れ直しても和集合で持つ
1156
+ * (前の世代にしか無いキーのバインドも失敗として報告させるため)。
1157
+ */
1158
+ private _pendingReapplyPaths;
1159
+ /**
1160
+ * これまでのどの世代かで再帰レジストリが実体化した具体パス(`nodes.*.total` 等)の累積。
1161
+ * 再セットのたびに `forgetGenerated` の戻り値を足し、`_rebuildPathInfo` の除外に使う。
1162
+ *
1163
+ * 除外は**世代を跨いで累積する**。読みを挟まない連続した再セットでも、生成アクセサの具体パスを
1164
+ * 指す静的辺(`nodes.*` → `nodes.*.total`)が戻らないことは、
1165
+ * `__tests__/integration.stateGenerationReset.test.ts` の
1166
+ * 「読みを挟まない 3 連続の再セットで静的辺が戻らない」が固定する。
1167
+ */
1168
+ private _generatedPaths;
1169
+ private _watchPaths;
1170
+ private _scanPaths;
1171
+ private _version;
1172
+ private _rootNode;
1173
+ private _boundComponent;
1174
+ private _boundComponentStateProp;
1175
+ private _hasMounts;
1176
+ private _hasGraftedVolumes;
1177
+ /** 読み書き境界の hook(設計案 H1)。宣言が要求する機能の分だけ付く */
1178
+ private _addressHooks;
1179
+ private _bindableEventMap;
1180
+ private _commandTokenNames;
1181
+ private _eventTokenNames;
1182
+ private _treeless;
1183
+ private _connectGeneration;
1184
+ constructor();
1185
+ private get _state();
1186
+ private set _state(value);
1187
+ attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void;
1188
+ private _loadFromSsrElement;
1189
+ /** state / src / json / inner <script> / API set のソース解決(_initialize とボリュームで共用)。 */
1190
+ private _loadStateFromSource;
1191
+ /**
1192
+ * 初回マウントのロードと登録。戻り値は「この接続で初期化を**完了**したか」で、
1193
+ * `false` は失敗ではなく**中断**(ロード中に要素が剥がされた — 下の注記)。
1194
+ */
1195
+ private _initialize;
1196
+ /**
1197
+ * 設定エラーでの fail-fast。initializePromise 等を解決してから raise する —
1198
+ * 未解決のまま投げると waitForStateInitialize(ホストの buildBindings)が
1199
+ * この要素を待ち続け、**ページ全体が無言でウェッジする**(1 つの設定ミスが
1200
+ * 無関係なバインディングまで道連れにする)。エラー自体は unhandled rejection
1201
+ * として loud に残る。
1202
+ */
1203
+ private _failInitialization;
1204
+ /**
1205
+ * `_initialize` の失敗の着地(#257)。旧挙動は「throw が connectedCallback の外へ
1206
+ * 出るだけ」で、`_initializePromise` も `_connectedCallbackPromise` も永久に未解決の
1207
+ * まま残り、作者が受け取るのは診断ではなく無言のハングだった。載るのは
1208
+ * `_initialize` が投げうるもの全部 — `_state` セッタの宣言検証($recursion /
1209
+ * $commandTokens / $eventTokens / $on / $streams / $listKeys / $watch)、
1210
+ * `_loadStateFromSource` のロード失敗(src の拡張子・json のパース・内包スクリプト・
1211
+ * 外部モジュール)、SSR データの merge、そして `setStateElement` の
1212
+ * 「1 rootNode 1 ツリー」違反(**別の**要素が 2 本目に来た形 — 同じ要素の再登録は
1213
+ * 冪等なので、ロード中の remove → append はここへ来ない)。
1214
+ *
1215
+ * 載**らない**もの: ロード中に要素が剥がされた形。作者のミスが 1 つも無いので
1216
+ * 初期化失敗ではなく中断として扱う(`_initialize` が `false` を返す)。
1217
+ *
1218
+ * もう 1 つ載らないのがボリューム(`mount=`)の失敗。`_initializeVolume` の catch が
1219
+ * 3 つの promise(initialize / loading / connectedCallback)を自分で解決してから raise し、
1220
+ * `connectedCallback` のボリューム分岐はそれを包まないので、ボリュームはこの着地に
1221
+ * 載らず connectedCallbackPromise を**拒否しない**。自前の報告が出るかどうかは失敗の
1222
+ * 種類による。報告が無い形では、逃げ方は `name=`(`_failInitialization` の注記)と
1223
+ * 同じで、throw はカスタム要素リアクションが捨てる戻り Promise へ出ていく
1224
+ * (ブラウザのコンソールには "Uncaught (in promise)" として残るが、promise を待つ側
1225
+ * = renderToString・mount・テストレシピには届かない)。失敗箇所ごとの正確な挙動は
1226
+ * `__tests__/integration.initFailureDiagnostics.test.ts` が固定している。挙動はこの
1227
+ * PR では変えない(枠の寿命は別 Issue)。
1228
+ *
1229
+ * `connectedCallback` が `_initialize` より前に await する 2 つ
1230
+ * (DCC の接続 — dcc/dccLifecycle.ts が内部面の `failInitializeLoudly` で載せる — と、
1231
+ * `bind-component` の preparing)の raise も同じ着地に載る。
1232
+ * 特に「初期化に失敗した要素の再接続」は `bindWebComponent` → `setInitialState` の
1233
+ * 復旧不能 raise でそこへ来るので、包まないと診断ゼロで素通りする。
1234
+ *
1235
+ * `_failInitialization`(設定エラーの fail-fast)との違いは 1 つ:
1236
+ * **connectedCallbackPromise を reject する**。ここまで来た要素は state を 1 つも
1237
+ * 持たない = このツリーは存在しない。resolve すると、それを待つ消費者
1238
+ * (@wcstack/server の renderToString・@wcstack/testing の mount・README の
1239
+ * テストレシピ)に「準備完了」と嘘をつく。下の SSR 経路(_rejectConnectedCallback)と
1240
+ * 同じ規範で、そちらと同じく**元のエラーをそのまま**投げ直す。
1241
+ *
1242
+ * `initializePromise` は従来どおり**解決**する(reject しない)。
1243
+ * `waitForStateInitialize` はページ中の全 `<wcs-state>` の initializePromise を
1244
+ * `Promise.all` で待つので、reject にすると 1 要素の設定ミスが無関係な
1245
+ * バインディングまで道連れになる(_failInitialization の注記と同じ理由)。
1246
+ *
1247
+ * 後始末はしない: `_initialized` を立てないので `disconnectedCallback` は初期化前
1248
+ * ガードで抜ける。`$listKeys` / `$watch` のようにセッタの後半で落ちた形では
1249
+ * `$on` の購読と stream registry が残るが、この要素は復旧不能(setInitialState が
1250
+ * throw する)なので、残骸は要素ごと捨てる前提で放置する。
1251
+ *
1252
+ * `ownsTree` が false の着地は、この要素だけを失敗させてルートに触らない。`mount=` の
1253
+ * readiness barrier(要件 D23)が使う: ボリュームはツリーの持ち主ではなく、ルートより先に
1254
+ * 接続したボリュームでは rootNode にまだ誰も居ないので、既定の着地だとまだ来ていないルートの
1255
+ * ノードを利用不能と印付けし、保留中の他のボリュームまで落としてしまう。
1256
+ */
1257
+ private _failInitializeLoudly;
1258
+ private _callStateConnectedCallback;
1259
+ private _callStateDisconnectedCallback;
1260
+ connectedCallback(): Promise<void>;
1261
+ disconnectedCallback(): void;
1262
+ get initialized(): boolean;
1263
+ /**
1264
+ * ライフサイクル機能(core/lifecycleHooks.ts、設計案 H3)へ開く内部面。接続を引き取った機能が
1265
+ * 要素の初期化を所有するために要る最小限。
1266
+ */
1267
+ get connectedRootNode(): Node | null;
1268
+ clearConnectedRootNode(): void;
1269
+ markInitialized(): void;
1270
+ settleInitialization(): void;
1271
+ loadStateFromSource(): Promise<Record<string, any>>;
1272
+ markTreeless(): void;
1273
+ /** 初期化失敗の着地(`_failInitializeLoudly`)。接続を引き取った機能が自分の失敗を載せる */
1274
+ failInitializeLoudly(error: unknown): never;
1275
+ get connectGeneration(): number;
1276
+ setWatchPaths(paths: ReadonlySet<string> | null): void;
1277
+ setScanPaths(paths: ReadonlySet<string> | null): void;
1278
+ /** 設定エラーの着地(`_failInitialization` の raise を除いた部分)。引き取った機能が使う */
1279
+ landInitialization(): void;
1280
+ setRecursionRegistry(registry: RecursionRegistry | null): void;
1281
+ addGeneratedPath(path: string): void;
1282
+ setBoundComponent(component: Element | null, stateProp: string | null): void;
1283
+ get initializePromise(): Promise<void>;
1284
+ get connectedCallbackPromise(): Promise<void>;
1285
+ get listPaths(): Set<string>;
1286
+ get listKeys(): ListKeyMap | null;
1287
+ get hasRecursion(): boolean;
1288
+ get recursionRegistry(): RecursionRegistry | null;
1289
+ get watchPaths(): ReadonlySet<string> | null;
1290
+ get scanPaths(): ReadonlySet<string> | null;
1291
+ get elementPaths(): Set<string>;
1292
+ /**
1293
+ * ボリューム(webComponent/volume.ts)のアクセサ登録: ツリーパスをキーにした
1294
+ * quoted-path アクセサを state オブジェクトに定義し、getter / setter 台帳と
1295
+ * 依存グラフに載せる。ルートのワイルドカード getter(`"children.*.label"`)と
1296
+ * 同じ機構に乗るので、評価は pushAddress 下・依存はグラフに載る。
1297
+ */
1298
+ /** ボリュームの watch パスをホットパス用ゲート(watchPaths)へ合流させる。 */
1299
+ addVolumeWatchPaths(paths: ReadonlySet<string>): void;
1300
+ /** ボリュームの $listKeys(接頭辞翻訳済み)をルートの表へ合流させる。衝突は設定ミス。 */
1301
+ mergeVolumeListKeys(entries: ReadonlyMap<string, ListKeySpec>): void;
1302
+ /** ボリュームが $updatedCallback を持つとき、収集ゲートを開ける(apply/applyChange.ts)。 */
1303
+ enableUpdatedCallback(): void;
1304
+ /** enable-ssr スナップショットから初期化されたか(D14 — webComponent/volume.ts が読む)。 */
1305
+ get hydratedFromSsr(): boolean;
1306
+ addListPath(path: string): void;
1307
+ findStateDescriptor(path: string): PropertyDescriptor | undefined;
1308
+ defineTreeAccessor(path: string, descriptor: PropertyDescriptor): void;
1309
+ get getterPaths(): Set<string>;
1310
+ get setterPaths(): Set<string>;
1311
+ get loopContextStack(): ILoopContextStack;
1312
+ get dynamicDependency(): Map<string, string[]>;
1313
+ get staticDependency(): Map<string, string[]>;
1314
+ get version(): number;
1315
+ /** state の世代(キャッシュ項目の印の正本 — cache/types.ts の `generation`)。 */
1316
+ get stateGeneration(): number;
1317
+ get rootNode(): Node;
1318
+ get boundComponentStateProp(): string | null;
1319
+ get hasMounts(): boolean;
1320
+ /** 唯一の呼び手は webComponent/mount.ts の registerMountRecord(Phase 2)。 */
1321
+ markHasMounts(): void;
1322
+ get hasGraftedVolumes(): boolean;
1323
+ get addressHooks(): IAttachedHooks | null;
1324
+ /** 宣言 `declaration` が要求する機能 `feature` の hook をこの state に付ける(未 install なら throw、D13) */
1325
+ attachAddressHooks(feature: string, declaration: string): void;
1326
+ /** 唯一の呼び手は webComponent/volume.ts の graftVolume(D22 後段のガードが読む)。 */
1327
+ markHasGraftedVolumes(): void;
1328
+ /** ボリュームがこのルートに予約された(接ぎ木前でも、予約下の読みは undefined が正 — D22) */
1329
+ markHasVolume(): void;
1330
+ /** スコープ機能(マウント・ボリューム)の hook をこの state に付ける(冪等) */
1331
+ private _attachScopeHooks;
1332
+ get bindableEventMap(): Record<string, string>;
1333
+ get commandTokenNames(): ReadonlySet<string>;
1334
+ get eventTokenNames(): ReadonlySet<string>;
1335
+ setBindableEventMap(map: Record<string, string>): void;
1336
+ private _addDependency;
1337
+ /**
1338
+ * source, target
1339
+ *
1340
+ * products.*.price => products.*.tax
1341
+ * get "products.*.tax"() { return this["products.*.price"] * 0.1; }
1342
+ *
1343
+ * products.*.price => products.summary
1344
+ * get "products.summary"() { return this.$getAll("products.*.price", []).reduce(sum); }
1345
+ *
1346
+ * categories.*.name => categories.*.products.*.categoryName
1347
+ * get "categories.*.products.*.categoryName"() { return this["categories.*.name"]; }
1348
+ *
1349
+ * @param sourcePath
1350
+ * @param targetPath
1351
+ */
1352
+ addDynamicDependency(sourcePath: string, targetPath: string): boolean;
1353
+ /**
1354
+ * source, target
1355
+ * products => products.*
1356
+ * products.* => products.*.price
1357
+ * products.* => products.*.name
1358
+ *
1359
+ * @param sourcePath
1360
+ * @param targetPath
1361
+ */
1362
+ addStaticDependency(sourcePath: string, targetPath: string): boolean;
1363
+ setPathInfo(path: string, bindingType: BindingType, source?: PathInfoSource): void;
1364
+ /**
1365
+ * 再セットで消した経路情報を、生き残ったバインドの登録から作り直す(issue #258 の X7)。
1366
+ *
1367
+ * `_pathSet.clear()` は残す。あのクリアには、`forgetGeneration` が外した静的辺を「行が
1368
+ * 作り直されたときに登録し直させる」自己修復が乗っている(辺が戻ることは
1369
+ * `__tests__/integration.stateGenerationReset.test.ts` の
1370
+ * 「静的な辺 nodes.* → nodes.*.total が戻る」が固定する)。消したうえで、生きているバインド
1371
+ * ぶんだけ `setPathInfo` をやり直す — `$recursion` のアンカーで既に同じことをしている手口を、
1372
+ * バインド全体へ広げたもの。
1373
+ *
1374
+ * `_generatedPaths`(これまでの世代の生成アクセサの具体パス)は張り直さない。行バインドが
1375
+ * 名指していても、新しい世代ではまだ実体化されていないため(recursion/generation.ts)。読みが
1376
+ * 実体化したときに `defineTreeAccessor` が登録し直す。
1377
+ *
1378
+ * 作り直すのはバインドが登録したパスだけ(`_pathRegistrations` の `bound`・#270)。`$watch` /
1379
+ * `$scan` だけの登録は飛ばす — 作り直しの後で今の世代の宣言が自分で登録し直し、そこで存在も
1380
+ * 検査される。ここで `_pathSet` に入れてしまうと、宣言側の `setPathInfo` が `_pathSet.has` で
1381
+ * 素通りし、両方の世代で宣言し続けたパスが新しい state で消えても報告されない。
1382
+ *
1383
+ * 反復中に `setPathInfo` が台帳へ書き戻す(既存キーの上書きのみで新キーは増えない)ので、
1384
+ * 誤解を避けるためスナップショットを取ってから回す。
1385
+ */
1386
+ private _rebuildPathInfo;
1387
+ private _createState;
1388
+ createStateAsync(mutability: Mutability, callback: (state: IStateProxy) => Promise<void>): Promise<void>;
1389
+ createState(mutability: Mutability, callback: (state: IStateProxy) => void): void;
1390
+ nextVersion(): number;
1391
+ get hasUpdatedCallback(): boolean;
1392
+ get hasErrorCallback(): boolean;
1393
+ get crossRowListPaths(): ReadonlySet<string>;
1394
+ addCrossRowListPath(path: string): void;
1395
+ get indexDependentGetterPaths(): ReadonlySet<string>;
1396
+ addIndexDependentGetterPath(path: string): void;
1397
+ setInitialState(state: Record<string, any>): void;
1398
+ /** 確立済みのバインドを今の世代で適用し直す(#267)。行のバインドは経路情報の台帳のパスから引く。 */
1399
+ private _reapplyBindings;
1400
+ }
1401
+
1402
+ /**
1403
+ * entries/core.ts — `@wcstack/state/core`(設計案 §4)。
1404
+ *
1405
+ * core だけの公開面。機能(watch / scan / streams・スコープ・再帰・SSR・devtools)は 1 つも
1406
+ * import しない — ページが `installFeatures([...])` で入れる。full(`@wcstack/state`)は
1407
+ * この面に機能と `Ssr` などを足したもので、公開 API は従来どおり。
1408
+ */
1409
+
1410
+ declare global {
1411
+ interface HTMLElementTagNameMap {
1412
+ "wcs-state": State;
1413
+ }
1414
+ }
1415
+
1416
+ export { TRUSTED_TYPES_POLICY_SLOT, VERSION, bootstrapCore as bootstrapState, buildBindings, defineState, getBindingsReady, getConfig, getTrustedTypesPolicy, setTrustedTypesPolicy };
1417
+ export type { IBindingErrorInfo, IWcsTrustedTypesPolicy, IWritableConfig, IWritableTagNames, WcsPathValue, WcsPaths, WcsStateApi, WcsThis };