@wcstack/state 3.5.4 → 4.0.0-rc.2

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 (82) hide show
  1. package/README.ja.md +669 -428
  2. package/README.md +667 -426
  3. package/dist/auto.min.js +1 -2
  4. package/dist/define.d.ts +4 -8
  5. package/dist/define.js +1 -1
  6. package/dist/index.d.ts +139 -1483
  7. package/dist/index.esm.js +1 -2
  8. package/dist/manifest.d.ts +18 -59
  9. package/dist/manifest.esm.js +542 -1202
  10. package/dist/parser.d.ts +49 -103
  11. package/dist/parser.esm.js +662 -831
  12. package/dist/split/auto.js +1 -0
  13. package/dist/split/chunks/chunk-732CB4QN.js +1 -0
  14. package/dist/split/chunks/chunk-7PN5YNZZ.js +1 -0
  15. package/dist/split/chunks/chunk-FF6KHTYS.js +1 -0
  16. package/dist/split/chunks/chunk-HFKGUDDJ.js +1 -0
  17. package/dist/split/chunks/chunk-PKDBVBAP.js +1 -0
  18. package/dist/split/chunks/chunk-QI7P7YPP.js +1 -0
  19. package/dist/split/chunks/chunk-QQH6N5CJ.js +1 -0
  20. package/dist/split/chunks/chunk-UM3O6QXD.js +1 -0
  21. package/dist/split/chunks/chunk-WEL3YSG7.js +1 -0
  22. package/dist/split/chunks/chunk-WWJNAZVP.js +1 -0
  23. package/dist/split/chunks/chunk-YOPPVWPQ.js +1 -0
  24. package/dist/split/core.d.ts +114 -1168
  25. package/dist/split/core.js +1 -2
  26. package/dist/split/features/devtools.d.ts +23 -3
  27. package/dist/split/features/devtools.js +1 -2
  28. package/dist/split/features/diagnostics.d.ts +27 -5
  29. package/dist/split/features/diagnostics.js +1 -2
  30. package/dist/split/features/formats.d.ts +21 -5
  31. package/dist/split/features/formats.js +1 -2
  32. package/dist/split/features/list-keys.d.ts +24 -0
  33. package/dist/split/features/list-keys.js +1 -0
  34. package/dist/split/features/recursion.d.ts +23 -3
  35. package/dist/split/features/recursion.js +1 -2
  36. package/dist/split/features/scopes.d.ts +25 -4
  37. package/dist/split/features/scopes.js +1 -2
  38. package/dist/split/features/ssr.d.ts +23 -3
  39. package/dist/split/features/ssr.js +1 -2
  40. package/dist/split/features/temporal.d.ts +19 -4
  41. package/dist/split/features/temporal.js +1 -2
  42. package/dist/wcs-manifest.json +43 -49
  43. package/package.json +15 -17
  44. package/dist/auto.min.js.map +0 -1
  45. package/dist/index.esm.js.map +0 -1
  46. package/dist/split/chunks/binder.js +0 -2
  47. package/dist/split/chunks/binder.js.map +0 -1
  48. package/dist/split/chunks/checkDependency.js +0 -2
  49. package/dist/split/chunks/checkDependency.js.map +0 -1
  50. package/dist/split/chunks/declarationAliases.js +0 -2
  51. package/dist/split/chunks/declarationAliases.js.map +0 -1
  52. package/dist/split/chunks/declarationHooks.js +0 -2
  53. package/dist/split/chunks/declarationHooks.js.map +0 -1
  54. package/dist/split/chunks/diagnosticsHooks.js +0 -2
  55. package/dist/split/chunks/diagnosticsHooks.js.map +0 -1
  56. package/dist/split/chunks/errorGuidance.js +0 -2
  57. package/dist/split/chunks/errorGuidance.js.map +0 -1
  58. package/dist/split/chunks/featureBridge.js +0 -2
  59. package/dist/split/chunks/featureBridge.js.map +0 -1
  60. package/dist/split/chunks/features.d.ts +0 -29
  61. package/dist/split/chunks/filterRegistry.js +0 -2
  62. package/dist/split/chunks/filterRegistry.js.map +0 -1
  63. package/dist/split/chunks/getAllPropertyDescriptors.js +0 -2
  64. package/dist/split/chunks/getAllPropertyDescriptors.js.map +0 -1
  65. package/dist/split/chunks/lifecycleHooks.js +0 -2
  66. package/dist/split/chunks/lifecycleHooks.js.map +0 -1
  67. package/dist/split/chunks/pathDiagnostics.js +0 -2
  68. package/dist/split/chunks/pathDiagnostics.js.map +0 -1
  69. package/dist/split/chunks/registerComponents.js +0 -2
  70. package/dist/split/chunks/registerComponents.js.map +0 -1
  71. package/dist/split/chunks/setAll.js +0 -2
  72. package/dist/split/chunks/setAll.js.map +0 -1
  73. package/dist/split/chunks/version.js +0 -2
  74. package/dist/split/chunks/version.js.map +0 -1
  75. package/dist/split/core.js.map +0 -1
  76. package/dist/split/features/devtools.js.map +0 -1
  77. package/dist/split/features/diagnostics.js.map +0 -1
  78. package/dist/split/features/formats.js.map +0 -1
  79. package/dist/split/features/recursion.js.map +0 -1
  80. package/dist/split/features/scopes.js.map +0 -1
  81. package/dist/split/features/ssr.js.map +0 -1
  82. package/dist/split/features/temporal.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,955 +1,141 @@
1
- /**
2
- * list/listKeys.ts
3
- *
4
- * `$listKeys: { <listPath>: <fieldName | (row) => key> }` 宣言マップを解析し、
5
- * 「リストパス → キー指定」表を構築する(docs/state-list-key-design.md §3)。
6
- *
7
- * この表が存在するリストパスへの配列代入は、setByAddress でキー突合され、
8
- * 一致行は旧オブジェクトを据え置いたまま変化フィールドだけが per-path 書き込みで
9
- * 流し込まれる(§2)。未宣言なら書き込み経路は従来と完全に同一。
10
- *
11
- * 「そのパスが実際にリストか」は宣言時には判定できない(listPaths は
12
- * バインディング収集時に確定する)。実行時に配列でなければ経路に入らないだけで、
13
- * 宣言自体はエラーにしない。
14
- */
15
-
16
- /** キー指定: フラットなフィールド名、または行から複合キーを作る関数 */
17
- type ListKeySpec = string | ((row: any) => unknown);
18
- type ListKeyMap = ReadonlyMap<string, ListKeySpec>;
19
-
20
- /**
21
- * Interface for hierarchical loop index management in nested loops.
22
- * Tracks parent-child relationships, versions, and provides access to index hierarchy.
23
- */
24
- interface IListIndex {
25
- readonly parentListIndex: IListIndex | null;
26
- readonly uuid: string;
27
- readonly position: number;
28
- readonly length: number;
29
- index: number;
30
- readonly version: number;
31
- readonly dirty: boolean;
32
- readonly indexes: number[];
33
- readonly listIndexes: WeakRef<IListIndex>[];
34
- readonly varName: string;
35
- at(position: number): IListIndex | null;
36
- }
37
- interface ILoopContext extends IStateAddress {
38
- readonly pathInfo: IPathInfo;
39
- readonly listIndex: IListIndex;
40
- }
41
- interface ILoopContextStack {
42
- createLoopContext(elementStateAddress: IStateAddress, callback: (loopContext: ILoopContext) => void | Promise<void>): void | Promise<void>;
43
- }
44
-
45
- declare const setLoopContextSymbol: unique symbol;
46
- declare const getByAddressSymbol: unique symbol;
47
- declare const hasByAddressSymbol: unique symbol;
48
- declare const connectedCallbackSymbol: unique symbol;
49
- declare const disconnectedCallbackSymbol: unique symbol;
50
- declare const updatedCallbackSymbol: unique symbol;
51
- declare const errorCallbackSymbol: unique symbol;
52
-
53
- interface IStateHandler extends ProxyHandler<IState> {
54
- readonly stateElement: IStateElement;
55
- readonly addressStackLength: number;
56
- /**
57
- * アドレススタックの先頭(いま評価しているアドレス)。ループ文脈の無いスコープでは null。
58
- * 再帰の深さ解決(recursion/bind.ts)もここだけを見る — 添字の供給元
59
- * (getContextListIndex / `$getAll` の省略形)が先頭しか見ないので、深さだけを外側の
60
- * フレームから拾うと「深さはあるが行が無い」定義にない状態になる。
61
- */
62
- readonly lastAddressStack: IStateAddress | null;
63
- readonly loopContext: ILoopContext | null | undefined;
64
- /**
65
- * 依存追跡の抑止中か。$untrackDependency のスコープ内、および setter 実行中
66
- * (setter は命令的な代入であって派生ではないため、その中の読み取りで依存を
67
- * 張らない)は true。checkDependency / $1 インデックス依存の登録が抑止される。
68
- */
69
- readonly untracking: boolean;
70
- /**
71
- * このプロキシの書き込み能力。書き込み API の入口(proxy/assertWritable.ts)が検査する — set
72
- * トラップを通らない `$resolve` / `$setAll` も readonly では書けない(要件 B6)。省略は writable。
73
- */
74
- readonly mutability?: Mutability;
75
- pushAddress(address: IStateAddress | null): void;
76
- popAddress(): IStateAddress | null;
77
- setLoopContext(loopContext: ILoopContext | null): void;
78
- clearLoopContext(): void;
79
- beginUntrack(): void;
80
- endUntrack(): void;
81
- }
82
- interface IStateProxy extends IState {
83
- [setLoopContextSymbol](loopContext: ILoopContext | null, callback: () => any): any;
84
- [getByAddressSymbol](address: IStateAddress): any;
85
- [hasByAddressSymbol](address: IStateAddress): boolean;
86
- [connectedCallbackSymbol](): Promise<void>;
87
- [disconnectedCallbackSymbol](): void;
88
- [updatedCallbackSymbol](updatedAbsAddressList: IAbsoluteStateAddress[]): void;
89
- [errorCallbackSymbol](error: unknown, info: IBindingErrorInfo): void;
90
- }
91
- type Mutability = "readonly" | "writable";
92
-
93
- type ParseBindTextResult = IParsedBinding;
94
-
95
- /**
96
- * Filter/types.ts
97
- *
98
- * Type definition file for filter functions.
99
- *
100
- * Main responsibilities:
101
- * - Defines types for filter functions (FilterFn) and filter functions with options (FilterWithOptionsFn)
102
- * - Type-safe management of filter name-to-function mappings (FilterWithOptions) and filter function arrays (Filters)
103
- * - Defines types for retrieving filter functions from built-in filter collections
104
- *
105
- * Design points:
106
- * - Type design enabling flexible filter design and extension
107
- * - Supports filters with options and combinations of multiple filters
108
- */
109
- type FilterFn<T = unknown> = (value: unknown) => T;
110
-
111
- /**
112
- * パース結果の変換フック(Phase 2 のマウント — impl-plan §3-0 の 1)。
113
- * マウントされたスコープの収集は、これで各パース結果を親ツリーの絶対パスへ書き換える。
114
- * `uuid` を持つエントリ(構造フラグメントの参照)には掛けない — フラグメント側の
115
- * パース結果は登録時(collectStructuralFragments)に変換済みで、二重に掛けると
116
- * 接頭辞が二重になる。
117
- */
118
- type ParseResultTransform = (parsed: ParseBindTextResult, forPath?: string) => ParseBindTextResult;
119
- interface IDeferredSpreadEntry {
120
- readonly node: Node;
121
- readonly tagName: string;
122
- readonly parseResults: ParseBindTextResult[];
123
- readonly transform?: ParseResultTransform;
124
- /** 予約中の定義待ちの取り消し(`scheduleDeferredSpreads` が持つ。行の活性化し直しで待ちを重ねない) */
125
- cancel?: () => void;
126
- }
127
-
128
- interface IContent {
129
- readonly firstNode: Node | null;
130
- readonly lastNode: Node | null;
131
- readonly mounted: boolean;
132
- appendTo(targetNode: Node): void;
133
- mountAfter(targetNode: Node): void;
134
- unmount(): void;
135
- /**
136
- * 自分のノードを DOM に残したままの解体(#4)。行の置き換えで `for` が同じ位置の Content を
137
- * 新しい行に使い回すとき、入力中の欄を DOM から外さずに unmount と同じ後始末をする。
138
- */
139
- unmountInPlace(): void;
140
- /**
141
- * wholesale 破棄: 全行クリアで再利用されない content の binding teardown
142
- * (listener 解除・アドレス台帳・loopContext 掃除)を省略し、ノード・binding
143
- * もろとも GC に任せる。定義待ち等の副作用がある場合は false を返し、呼び出し側が
144
- * 従来経路(deactivate + unmount)で解体する。
145
- */
146
- tryDestroy(): boolean;
147
- /**
148
- * まだ展開していない、未定義カスタム要素への spread(#330)。持つ行だけに付く(形を増やさない)。
149
- * 活性化のたびに定義待ちへ予約し、展開したものは外れる
150
- */
151
- spreads?: IDeferredSpreadEntry[];
152
- }
153
-
154
- /**
155
- * core/addressHooks.ts — 読み書き境界の受け口(設計案 H1、S3)。
156
- *
157
- * 機能は `install()` でレジストリに hook 実装を置く(hot path には触れない)。state 要素は
158
- * 宣言が要求する機能の hook だけを `attachAddressHooks` で自分に付け、core の各受け口は
159
- * `stateElement.addressHooks` が null なら判定 1 回で抜ける
160
- * (調査 §10.8: 大域配列の走査は読み +40%、state ごとの門なら +0.1 ns)。
161
- * 宣言が要求する機能が未 install なら `requireFeature` が宣言時に throw する(readiness barrier、D13)。
162
- *
163
- * 受け口(core 側の呼び出し点):
164
- * read getByAddress の先頭(キャッシュより前)。名前空間・マーカーなど raw state に無い値を答える
165
- * readMissing getByAddress で「ツリーにそのキーが無い」と分かった点(親の値つき。親が無ければ null)
166
- * write setByAddress の先頭。書き込みを奪うか、禁止して throw する
167
- * writeMissing setByAddress の fast path で「親にそのキーが無い」と分かった点(公開 getter への書き込み)
168
- * writeObserve 旧値が分かった点(同値ガードの直後)。旧値の台帳を持つ機能が読む
169
- * written 書き込み・`$postUpdate` の後。観測面へ通知する機能が読む
170
- * swapped 要素の入れ替えで行が動いた点(旧値の台帳を行に追従させる)
171
- * get get トラップの文字列プロパティ先頭。API・名前空間・パスの翻訳を答える
172
- * indexShift `$n` の解決点。スコープ相対の段ずれを足す
173
- * handlerScope イベントハンドラの添字の段数を決める点
174
- * updated `$updatedCallback` の後。相対配送する機能が読む
175
- * suppressPathDiagnostic 束縛時の未宣言パス診断を黙らせるか(予約済みスロットの配下など)
176
- * rowReused その場で使い回した行(DOM から外れない)の点。行の中のスコープを新しい listIndex へ張り直す
177
- */
178
-
179
- type ReadHook = (stateElement: IStateElement, address: IStateAddress, receiver: any, handler: IStateHandler) => unknown;
180
- type ReadMissingHook = (stateElement: IStateElement, address: IStateAddress, parentValue: object | null, receiver: any, handler: IStateHandler) => unknown;
181
- type WriteHook = (stateElement: IStateElement, address: IStateAddress, value: unknown, receiver: any, handler: IStateHandler) => unknown;
182
- type WriteMissingHook = (stateElement: IStateElement, address: IStateAddress, parentValue: object, key: PropertyKey, value: unknown, receiver: any, handler: IStateHandler) => unknown;
183
- type WriteObserveHook = (stateElement: IStateElement, path: string, absAddress: IAbsoluteStateAddress, oldValue: unknown, hasOldValue: boolean) => void;
184
- type WrittenHook = (stateElement: IStateElement, pathInfo: IPathInfo, detail?: {
185
- readonly value: unknown;
186
- }) => void;
187
- type SwappedHook = (stateElement: IStateElement, elementAbsAddress: IAbsoluteStateAddress, displacedAbsAddress: IAbsoluteStateAddress) => void;
188
- type GetHook = (handler: IStateHandler, prop: string, receiver: any, target: object) => unknown;
189
- type IndexShiftHook = (handler: IStateHandler, lastAddress: IStateAddress) => number;
190
- /**
191
- * ハンドラが受け取る添字の段数を決める(`event/handler.ts`)。
192
- *
193
- * **合成は未定義** — この hook は畳み込み(前の hook の結果が次の `wildcardCount` になる)で
194
- * 呼ばれるが、現行唯一の実装(`webComponent/addressHooks.ts` の scopes)は「記録が引けて
195
- * shift が無ければ 0」を返す**吸収型**で、可換でも結合的でもない。2 つ目の実装が足されると
196
- * `0 - shift` のような負値になりうる。**実装は 1 つに保つこと**。2 つ目が要るなら、先に
197
- * 「答えを持たない hook は次へ渡す」規約(`NOT_HANDLED` を返す形。`read` / `write` と同じ)
198
- * へ寄せてから足す。
199
- */
200
- type HandlerScopeHook = (stateElement: IStateElement, node: Node, rootNode: Node, loopContext: ILoopContext, wildcardCount: number) => number;
201
- type UpdatedHook = (stateElement: IStateElement, refs: IAbsoluteStateAddress[], receiver: any) => void;
202
- type SuppressPathDiagnosticHook = (stateElement: IStateElement, path: string) => boolean;
203
- type RowReusedHook = (stateElement: IStateElement, content: IContent) => void;
204
- interface IAddressHooks {
205
- readonly read?: ReadHook;
206
- readonly readMissing?: ReadMissingHook;
207
- readonly write?: WriteHook;
208
- readonly writeMissing?: WriteMissingHook;
209
- readonly writeObserve?: WriteObserveHook;
210
- readonly written?: WrittenHook;
211
- readonly swapped?: SwappedHook;
212
- readonly get?: GetHook;
213
- readonly indexShift?: IndexShiftHook;
214
- readonly handlerScope?: HandlerScopeHook;
215
- readonly updated?: UpdatedHook;
216
- readonly suppressPathDiagnostic?: SuppressPathDiagnosticHook;
217
- readonly rowReused?: RowReusedHook;
218
- }
219
- /** state 要素に付いた hook 群(種類ごとに、機能の登録順) */
220
- type IAttachedHooks = {
221
- readonly [K in keyof Required<IAddressHooks>]: NonNullable<IAddressHooks[K]>[];
222
- };
223
-
224
- /**
225
- * pathDiagnostics.ts — パスに関する**エラーの文言**(throw する側)と、診断の両面が共有する部品。
226
- *
227
- * 束縛時の存在検査(`user.nmae` のような打ち間違いを console.warn で知らせる開発時の診断)は
228
- * `features/diagnostics` へ分けた(diagnostics/pathChecks.ts)。core に残るのは、実行を止める
229
- * エラーの文言と、その did-you-mean が使う候補の集め方だけ。エラーは機能の有無に関わらず
230
- * 読める文言で落ちなければならないので、ここは core から外せない。
231
- *
232
- * 診断 code はコンソール → lint → IDE の三面で共有する(errorGuidance.ts の規約)。
233
- */
234
- /** `setPathInfo` の呼び出し元の種別。診断 code と適用範囲がこれで変わる */
235
- type PathInfoSource =
236
- /** data-wcs / mustache / コメントバインディング */
237
- "binding"
238
- /** `$watch` の宣言キー */
239
- | "watch"
240
- /** `$scan` の `from` / `resetOn`(docs/state-scan-design.md §2-4) */
241
- | "scan"
242
- /** ランタイム内部のパス翻訳(mapped な bind-component の外向き伝播)。検査しない */
243
- | "internal";
244
-
245
- /**
246
- * 単一の自己再帰宣言。初版はアンカーと反復サブパスとも「固定プロパティ列の末尾に
247
- * `.*` がひとつ」の形に限定する(docs/state-recursive-path-impl-plan.md §1-1)。
248
- *
249
- * 例: `$recursion = { "nodes.*": "children.*" }`
250
- * - `anchor` … `"nodes.*"`(深さ 0 のノードパス)
251
- * - `repeat` … `"children.*"`(1 段深くする相対サブパス)
252
- * - `recursiveAnchor` … `"nodes.**"`
253
- * - `anchorList` … `"nodes"`
254
- * - `repeatList` … `"children"`
255
- *
256
- * リスト側の 2 つは宣言時に確定させる(静的側の `RecursionSpec` と同じ構成)。
257
- * 各所で `lastIndexOf(DELIMITER)` の slice を繰り返すと、綴りの取り違えが分散する。
258
- */
259
- interface IRecursionSpec {
260
- readonly anchor: string;
261
- readonly repeat: string;
262
- /** `anchor` の `**` 形(`"nodes.**"`)。オーサリング層のパス解析で使う。 */
263
- readonly recursiveAnchor: string;
264
- /** `anchor` のリスト側(`"nodes"` — 末尾の `.*` を落とした形)。 */
265
- readonly anchorList: string;
266
- /** `repeat` のリスト側(`"children"`)。 */
267
- readonly repeatList: string;
268
- }
269
- /**
270
- * 展開済みの再帰 getter 1 本ぶんの素性。生成アクセサに紐づくメタデータで、
271
- * ランタイムが読むのは深さ(`**` の束縛)と元の宣言(診断の名指し)の 2 つだけ。
272
- * 具体パスは台帳のキー、`PathInfo` は読む側が intern 済みのものを持つので、ここには
273
- * 重ねて持たない。
274
- */
275
- interface IRecursionAccessor {
276
- /** 元の宣言(`"nodes.**.total"`) */
277
- readonly recursivePath: string;
278
- /** 反復の段数(0 origin) */
279
- readonly depth: number;
280
- }
281
-
282
- /**
283
- * recursion/registry.ts
284
- *
285
- * state 1 つぶんの再帰レジストリ。宣言・`**` getter の定義・展開済みアクセサの台帳を
286
- * 持ち、「具体パスを読む直前に、その深さのアクセサを生やす」遅延実体化を担う。
287
- *
288
- * 遅延であることは実装の**不変条件**である(Phase A の A6/A7)。そのパスを一度でも
289
- * 読んでから生やしても、`isCacheable` が `wildcardCount > 0` だけでキャッシュ可を返す
290
- * ため `undefined` が `dirty:false` で固定され、以後どう書いても回復しない。
291
- * したがって実体化は `getByAddress` のキャッシュ参照**前**に置く(E5)。
292
- *
293
- * 寿命は state の世代と共にする。`_state` の再セットで `getterPaths` / `listPaths` は
294
- * クリアされるので、レジストリも作り直す(§1-3)。ただし**生やしたアクセサは state
295
- * オブジェクトの側に残る**ので、同じ state を再セットすると `getStateInfo` がそれを
296
- * `getterPaths` に復元する。そのとき「もう生えているから何もしない」と早期 return して
297
- * しまうと `listPaths` の登録だけが抜け落ちるため、生成物は WeakSet で見分けて
298
- * 登録だけをやり直す。
299
- */
300
-
301
- declare class RecursionRegistry {
302
- readonly spec: IRecursionSpec;
303
- private readonly _definitions;
304
- private readonly _accessors;
305
- /**
306
- * `recursiveGetterOwning` の記憶。キーは添字を `*` に畳んだ形(`nodes.1.total` と `nodes.2.total`
307
- * は 1 つ)、値は「その具体パスを展開形(またはその値の内側)として持つ `**` getter」、
308
- * 無ければ null。
309
- *
310
- * 有界である: キーは添字を畳んだワイルドカード形のパス文字列で、`PathInfo` が intern する集合
311
- * (バインディング・getter・API 引数に綴られたパスと、その展開形)の部分集合にしかならない。
312
- * intern 済みパスの集合が有界であることは D10 で受け入れ済みなので、ここも同じ上限に収まる。
313
- * 文字列は WeakSet に入らないので、寿命はレジストリ(= state の世代)と共にする。
314
- */
315
- private readonly _ownerByPath;
316
- /**
317
- * 書き込みのホットパス(`setByAddress`)向けの記憶。キーは intern 済みの `PathInfo` なので
318
- * 寿命と上限は PathInfo の intern 集合と同じ(WeakMap)。畳み(split + Number + join)は
319
- * miss のときだけ払う — 宣言のある state では**アンカー外を含む全書き込み**がここを通る
320
- * (第 4 サイクルで実測: 畳みを毎回払うと `s.counter = i` で +100ns/書き込み)。
321
- */
322
- private readonly _ownerByPathInfo;
323
- /**
324
- * 読みのホットパス(`getByAddress`)向けの記憶。`_ownerByPathInfo` と対称で、キーは
325
- * intern 済みの `PathInfo`、値は「そのパスの展開アクセサ」、展開形でなければ null。
326
- * 宣言のある state では**アンカー外を含む全読み**(親ウォークの各段を含む)がここを
327
- * 通るので、文字列キーの `Map.get` + `Set.has` + `startsWith` を毎回払わせない
328
- * (第 5 サイクルで実測)。
329
- *
330
- * 読みの否定判定の記憶は**ここ 1 つ**(第 5 サイクル再検証で文字列キーの `_nonAccessors` を撤去 —
331
- * 前段にこの記憶を置いた後は、PathInfo とパス文字列が 1:1 なので二重に持つだけだった)。
332
- * 否定を記憶してよい根拠は、定義集合が state の世代内で不変であること —
333
- * 同じ `PathInfo` は同じパス文字列なので、いちど「展開形でない」と決まった PathInfo が
334
- * 後から実体化されることはない。実体化した側は `materializeForPathInfo` が
335
- * `_define` の戻り値でそのまま記憶を更新する(否定が実体化を隠さない)。
336
- */
337
- private readonly _accessorByPathInfo;
338
- /** `concretePathAt` の記憶(接尾辞 → 深さ順の具体パス)。 */
339
- private readonly _concreteBySuffix;
340
- private readonly _registeredListPaths;
341
- constructor(spec: IRecursionSpec, state: object);
342
- /**
343
- * 作者が手で書いた具体パス(`get "nodes.*.children.*.total"()` / データプロパティ)が、宣言済み
344
- * `**` getter の展開形と同名でないことを**構築時に**確かめる。
345
- *
346
- * `_define` の衝突検査は「その深さを最初に読んだとき」にしか走らないので、データが浅い間は
347
- * 通り、木が 1 段深くなった瞬間にバインディングが落ちていた(第 3 サイクルのレビューで実測)。
348
- * 前世代の生成物(own に残った生成 getter)は衝突ではない — 同じ state の再セットで必ず居る。
349
- */
350
- private _assertNoConcreteCollision;
351
- /**
352
- * 2 本の `**` getter が同じ具体パスへ展開しないことを、宣言だけから静的に確かめる。
353
- *
354
- * 衝突するのは「片方の接尾辞がもう片方の接尾辞の末尾で、差分が反復語の整数倍」の
355
- * ときだけ(`nodes.**.total` と `nodes.**.children.*.total` は深さ k と k+1 で
356
- * 同じ `nodes.*.children.*.total` になる)。検出しないと `_definitions` の挿入順で
357
- * 最初に一致した方が無言で勝つ。
358
- */
359
- private _assertNoColliding;
360
- /**
361
- * `**` getter を 1 本でも宣言しているか。
362
- * **テスト・診断専用**(ランタイムの経路は `_definitions.size` を直接見る)。
363
- */
364
- get hasDefinitions(): boolean;
365
- /**
366
- * その接尾辞が宣言済みの `**` getter と衝突するなら、その getter のパスを返す。
367
- *
368
- * 完全一致だけでは足りない。①反復語の整数倍だけ違う接尾辞は同じ族を指す
369
- * (`_assertNoColliding` が宣言どうしについて既に見ている条件)②getter の**下**を
370
- * 指す形(`nodes.**.total.x` / 反復語ぶんずれた `nodes.**.children.*.total.x`)は、
371
- * getter が返したオブジェクトへ書いてキャッシュを汚し、次の無効化で無言に戻る。
372
- * どちらも書き込みの入口(列挙より前)で止める — 述語は expand.ts の `coversSuffix`。
373
- */
374
- conflictingRecursiveGetter(suffix: string): string | null;
375
- /**
376
- * `recursiveGetterOwning` の intern 済み `PathInfo` 版(書き込みのホットパス用)。
377
- * WeakMap の hit なら畳みも照合も払わない。
378
- */
379
- recursiveGetterOwningPath(pathInfo: IPathInfo): string | null;
380
- /**
381
- * 具体パスを展開形(またはその値の内側)として持つ `**` getter のパス。無ければ null。
382
- * **実体化はしない。**
383
- *
384
- * `conflictingRecursiveGetter` の**具体パス版**で、`**` を経ない 2 つの入口が使う:
385
- *
386
- * - バインド確立時のパス存在検査(`checkDeclaredPath`)。あの時点ではまだ生えて
387
- * いないので、素の存在検査では必ず「解決できない」になる。展開形そのもの
388
- * (`nodes.*.total`)だけでなく、その値の中を指す形(`nodes.*.stats.count` で
389
- * `get "nodes.**.stats"()` がオブジェクトを返す)も、通常の getter の下と同じく
390
- * 評価しないと分からないので黙る側に倒す。
391
- * - 書き込みの入口(`setByAddress`)。`$setAll("nodes.*.children.*.total", [], v)` や
392
- * `this["nodes.1.total"] = v` は `**` を含まないので `setAllRecursive` の
393
- * 読み取り専用検査を通らず、未実体化なら fast path が行オブジェクトへ素の
394
- * プロパティとして書いてしまう(ノードを汚し、代入値が `dirty:false` で載って
395
- * 以後 getter が評価されない)。展開形への書き込みは、実体化の前後に関わらず
396
- * `wcs/recursion-readonly` で止める。
397
- */
398
- recursiveGetterOwning(concretePath: string): string | null;
399
- /** 具体パスが宣言済み `**` getter の展開形そのものなら、その getter のパス。 */
400
- private _matchExpansion;
401
- /**
402
- * `materializeFor` の `PathInfo` 版。**読みのホットパス(`getByAddress`)専用**で、
403
- * 判定そのものは `materializeFor` に委ね、結果(否定を含む)を PathInfo に記憶する。
404
- * 書き側の `recursiveGetterOwningPath` と対称。
405
- */
406
- materializeForPathInfo(stateElement: IStateElement, pathInfo: IPathInfo): IRecursionAccessor | null;
407
- /**
408
- * 具体パスが再帰 getter の展開形なら、そのアクセサを(未登録なら生やして)返す。
409
- * 該当しなければ null。読みは `materializeForPathInfo` を通るので、ここへ来るのは
410
- * 記憶が外れたときだけ — 判定は接頭辞 1 回で抜け、ここでは否定を記憶しない(記憶は
411
- * `materializeForPathInfo` の PathInfo キーの 1 か所)。
412
- * (`**` getter の無い空レジストリを弾くのは呼び出し側の役目。)
413
- */
414
- materializeFor(stateElement: IStateElement, concretePath: string): IRecursionAccessor | null;
415
- private _define;
416
- /**
417
- * 経路上のリストパスを `listPaths` に載せる(E4)。`setPathInfo(path, "for")` は
418
- * 使えない — あちらは `elementPaths` にも入れて `setByAddress` の swap 経路
419
- * (`isSwappable`)を変えてしまう。ここで要るのは「依存ウォークがこのパスを
420
- * リストとして展開する」ことだけ。
421
- */
422
- private _registerListPaths;
423
- /**
424
- * この世代が生やしたもの(own の生成アクセサ・依存辺・キャッシュ)を忘れる(state の
425
- * 再セット時、`getStateInfo` の再収集より**前**に呼ぶ)。実体は generation.ts。
426
- */
427
- forgetGenerated(stateElement: IStateElement, previousState: object): ReadonlySet<string>;
428
- /**
429
- * `**` 接尾辞の深さ `depth` の具体パス(`concretePathAt` の記憶付き版)。
430
- * 束縛形の読み(`this["nodes.**.value"]` / 省略形 `$getAll`)は再帰 getter の評価ごとに
431
- * ここを通るので、深さぶんの文字列連結とワイルドカード数えを毎回やり直さない。
432
- * 上限は「接尾辞の種類 × 128」で有界(上限超過は `concretePathAt` が throw するので載らない)。
433
- */
434
- concretePathAt(suffix: string, depth: number): string;
435
- /** 展開済みアクセサのメタデータ(深さ解決・診断・テスト用)。 */
436
- accessorFor(concretePath: string): IRecursionAccessor | null;
437
- /**
438
- * これまでに実体化した具体パスの一覧。**テスト専用**(「読んだ深さだけが生える」という
439
- * 遅延実体化の不変条件を外から確かめる口。ランタイムはどの経路からも呼ばない)。
440
- */
441
- get materializedPaths(): ReadonlySet<string>;
442
- }
443
-
444
- interface IStateElement {
445
- /** DOM connection state; optional for non-DOM state implementations. */
446
- readonly isConnected?: boolean;
447
- /**
448
- * state のロードが完了しているか。`initializePromise` の同期版で、
449
- * DCC のアクセサが「今すぐ読み書きしてよいか」を判断するのに使う。
450
- * optional なのはテスト用モック互換のため(undefined は「不明=未初期化扱い」)。
451
- */
452
- readonly initialized?: boolean;
453
- readonly initializePromise: Promise<void>;
454
- readonly connectedCallbackPromise: Promise<void>;
455
- readonly listPaths: Set<string>;
456
- readonly elementPaths: Set<string>;
457
- readonly getterPaths: Set<string>;
458
- readonly setterPaths: Set<string>;
459
- readonly loopContextStack: ILoopContextStack;
460
- readonly dynamicDependency: Map<string, string[]>;
461
- readonly staticDependency: Map<string, string[]>;
462
- readonly version: number;
463
- /**
464
- * state の世代。`_state` の差し替えごとに 1 つ進み、キャッシュ項目の印になる
465
- * (cache/types.ts の `generation`)。`version`(更新サイクルの番号)とは別のカウンタ。
466
- * optional なのはテスト用モック互換のため(undefined のモックが載せた項目は
467
- * undefined 同士で一致し、従来どおりヒットする — `__tests__/proxy.getByAddress.test.ts`
468
- * の「キャッシュがある場合はキャッシュを返すこと」が固定する)。
469
- */
470
- readonly stateGeneration?: number;
471
- readonly rootNode: Node;
472
- readonly boundComponentStateProp: string | null;
473
- /**
474
- * `bind-component` で束ねられているコンポーネント要素(親スコープ側のノード)。
475
- * マッピング規則の引き当てに使う。optional なのはテスト用モック互換のため。
476
- */
477
- /**
478
- * この state の実体が innerState proxy(= 値の正本が親スコープの state にある
479
- * mapped な `bind-component`)か。真のときだけ越境アドレスの受け渡しと
480
- * リストパスの外向き伝播が働く(§1.8)。
481
- * optional なのはテスト用モック互換のため(undefined は plain 扱い)。
482
- */
483
- /**
484
- * この state element にマウント(Phase 2 の単一ツリー — webComponent/mount.ts)が
485
- * 1 つでも登録されているか。偽のとき getByAddress / isCacheable / `$n` 補正は
486
- * boolean 判定 1 個でオーバーレイ経路を抜ける(設計書 D18)。
487
- * optional なのはテスト用モック互換のため(undefined は「マウント無し」扱い)。
488
- */
489
- readonly hasMounts?: boolean;
490
- markHasMounts?(): void;
491
- /**
492
- * この state element に接ぎ木済みのボリューム(`mount=` — webComponent/volume.ts)が
493
- * 1 つでもあるか。偽のとき setByAddress の D22 後段ガード(マウントポイントを含む
494
- * 親の丸ごと書き検査)は boolean 判定 1 個で抜ける(設計書 D18 と同じ形)。
495
- * optional なのはテスト用モック互換のため(undefined は「ボリューム無し」扱い)。
496
- */
497
- readonly hasGraftedVolumes?: boolean;
498
- markHasGraftedVolumes?(): void;
499
- /** ボリュームがこのルートに予約・接ぎ木された: スコープ機能の hook を付ける(webComponent/addressHooks.ts) */
500
- markHasVolume?(): void;
501
- /**
502
- * ライフサイクル機能(core/lifecycleHooks.ts、設計案 H3)へ開く内部面。接続を引き取った機能が
503
- * 要素の初期化を所有するために要る最小限で、optional はテスト用モック互換のため。
504
- */
505
- /** いま接続している rootNode(未接続は null)。公開の `rootNode` と違い throw しない */
506
- readonly connectedRootNode?: Node | null;
507
- clearConnectedRootNode?(): void;
508
- /** 初期化完了の印(引き取った機能が自分の着地で立てる) */
509
- markInitialized?(): void;
510
- /** 初期化待ちの 3 つの promise を解決する(未解決のまま投げるとページが無言でウェッジする) */
511
- settleInitialization?(): void;
512
- /** `state` / `src` / 内包スクリプトからこの要素のソースを読む */
513
- loadStateFromSource?(): Promise<Record<string, any>>;
514
- /** 自分のツリーを持たずに初期化を終えた印(DCC 定義要素。再接続でこの rootNode のツリーとして登録し直さない) */
515
- markTreeless?(): void;
516
- /** 初期化失敗の着地(診断 1 件・connectedCallbackPromise の reject — #257)。常に throw する */
517
- failInitializeLoudly?(error: unknown): never;
518
- /** 接続の世代(接続の末尾の起動が、陳腐化した connect の再開を弾くために照合する) */
519
- readonly connectGeneration?: number;
520
- /** `$watch` / ボリュームの合流が決めた監視パス(setByAddress の旧値キャプチャのゲート) */
521
- setWatchPaths?(paths: ReadonlySet<string> | null): void;
522
- /** `$scan` の `from` パス(`watchPaths` と並ぶ旧値キャプチャのゲート) */
523
- setScanPaths?(paths: ReadonlySet<string> | null): void;
524
- /** 設定エラーの着地(初期化待ちの promise を解決し、二重着地の印を立てる) */
525
- landInitialization?(): void;
526
- /** `bind-component` が束ねた相手(`boundComponentStateProp` の答えになる) */
527
- setBoundComponent?(component: Element | null, stateProp: string | null): void;
528
- /** `$recursion` のレジストリ(宣言が無ければ null。`hasRecursion` の裏づけ) */
529
- setRecursionRegistry?(registry: RecursionRegistry | null): void;
530
- /** 前世代の再帰レジストリが生やした具体パス(経路情報の作り直しから除く) */
531
- addGeneratedPath?(path: string): void;
532
- /**
533
- * 読み書き境界の hook(core/addressHooks.ts、設計案 H1)。宣言が要求する機能の分だけ
534
- * `attachAddressHooks` で付く。無い state は null 判定 1 個で抜ける。optional はモック互換
535
- */
536
- readonly addressHooks?: IAttachedHooks | null;
537
- attachAddressHooks?(feature: string, declaration: string): void;
538
- /**
539
- * この state 要素に束ねられた(`setPathInfo` を通った)パスの集合。丸ごとマウント
540
- * (ルート規則)の親→子通知が「登録済みパス全部を読み直せ」を組み立てるのに使う
541
- * (webComponent/rootReloadPaths.ts)。
542
- * optional なのはテスト用モック互換のため(undefined は「登録なし」扱い)。
543
- */
544
- /**
545
- * DCC の `$bindables` から生成した「パス → 変更イベント名」表。
546
- * 唯一の書き手は defineDCC で、読み手は setByAddress。
547
- * getter だけを公開して setter をインターフェースから落としていたため
548
- * defineDCC が具象 State に依存していた(§3.5)。
549
- */
550
- readonly bindableEventMap: Record<string, string>;
551
- setBindableEventMap(map: Record<string, string>): void;
552
- readonly commandTokenNames: ReadonlySet<string>;
553
- readonly eventTokenNames: ReadonlySet<string>;
554
- /**
555
- * state が $updatedCallback を定義しているか。false のとき drain は更新
556
- * アドレスの集計と最終の writable createState を丸ごとスキップできる。
557
- * optional なのはテスト用モック互換のため(undefined は「不明=集計する」)。
558
- */
559
- readonly hasUpdatedCallback?: boolean;
560
- /**
561
- * state が $errorCallback を定義しているか。true のとき drain は隔離したバインディング
562
- * 適用失敗を console.error の代わりに $errorCallback へ配送する(devtools sink へは常に流す)。
563
- * optional なのはテスト用モック互換のため(undefined は「未定義=console.error」)。
564
- */
565
- readonly hasErrorCallback?: boolean;
566
- /**
567
- * 他行を読む getter(隣接項目参照など)が検出されたリストパスの集合。
568
- * これらのリストは walkDependency の diff-filter 展開の対象外(全行展開)。
569
- * optional なのはテスト用モック互換のため(undefined は「検出なし」扱い)。
570
- */
571
- readonly crossRowListPaths?: ReadonlySet<string>;
572
- addCrossRowListPath?(path: string): void;
573
- /**
574
- * 評価中に $1 等のインデックスを読んだ getter パスの集合(実行時検出)。
575
- * 位置だけが変わった行(listDiff.changeIndexSet)は index 以外の入力が不変なので、
576
- * walkDependency の静的子展開をこの集合の subtree に限定できる。
577
- * optional なのはテスト用モック互換のため(undefined は「検出なし」扱い)。
578
- */
579
- readonly indexDependentGetterPaths?: ReadonlySet<string>;
580
- addIndexDependentGetterPath?(path: string): void;
581
- /**
582
- * `$listKeys` 宣言から生成した「リストパス → キー指定」表。
583
- * 宣言が無ければ null / undefined で、setByAddress のキー突合経路に一切入らない
584
- * (docs/state-list-key-design.md §7-1 のゼロコスト契約)。
585
- * optional なのはテスト用モック互換のため(undefined は「宣言なし」扱い)。
586
- */
587
- readonly listKeys?: ListKeyMap | null;
588
- /**
589
- * `$watch` 宣言から生成した監視対象パスの集合。
590
- * 宣言が無ければ null / undefined で、setByAddress の旧値キャプチャには一切入らない
591
- * (docs/state-watch-hook-design.md §10 のゼロコスト契約)。
592
- * optional なのはテスト用モック互換のため(undefined は「宣言なし」扱い)。
593
- */
594
- readonly watchPaths?: ReadonlySet<string> | null;
595
- /**
596
- * `$scan` の `from` パスの集合(docs/state-scan-design.md §2-1)。`watchPaths` と並んで
597
- * setByAddress の旧値キャプチャのゲートになる(fold に `prev` を渡すため)。
598
- * 宣言が無ければ null / undefined。optional なのはテスト用モック互換のため。
599
- */
600
- readonly scanPaths?: ReadonlySet<string> | null;
601
- /**
602
- * パスを依存グラフへ登録する。DOM バインディング登録(BindingSession)のほか、
603
- * `$watch` 宣言(processWatchDeclaration)からも呼ばれる — 静的依存グラフに
604
- * 載るのがバインド済みパスだけだと headless 購読が成立しないため(設計書 §8)。
605
- *
606
- * `source` は存在検査の診断 code と適用範囲を決める(pathDiagnostics.ts)。
607
- * 省略時は `"binding"`(テスト用モック互換のため optional)。
608
- */
609
- /** ボリュームの宣言面の合流(webComponent/volume.ts 専用・実装は State のみ) */
610
- addVolumeWatchPaths?(paths: ReadonlySet<string>): void;
611
- mergeVolumeListKeys?(entries: ReadonlyMap<string, ListKeySpec>): void;
612
- enableUpdatedCallback?(): void;
613
- /** enable-ssr スナップショットから初期化されたか(D14)。 */
614
- readonly hydratedFromSsr?: boolean;
615
- /** ボリュームのアクセサ登録(webComponent/volume.ts 専用) */
616
- defineTreeAccessor(path: string, descriptor: PropertyDescriptor): void;
617
- /**
618
- * リストパスとしてだけ登録する(`listPaths` に足す)。`setPathInfo(path, "for")` は
619
- * `elementPaths` にも入れて `setByAddress` の swap 経路(`isSwappable`)を変えるので、
620
- * 「依存ウォークがこのパスをリストとして展開する」ことだけが要る用途には使えない
621
- * (docs/state-recursive-path-impl-plan.md §3-2 の E4)。
622
- */
623
- addListPath(path: string): void;
624
- /**
625
- * state オブジェクト自身+プロトタイプチェーンから descriptor を引く(生成物と作者定義の
626
- * 見分けに使う)。class 構文の getter は prototype に載るので own だけでは足りない。
627
- */
628
- findStateDescriptor(path: string): PropertyDescriptor | undefined;
629
- /**
630
- * この state に `$recursion` 宣言があるか。偽のとき getByAddress の遅延実体化と
631
- * get トラップの `**` 解決は boolean 判定 1 個で抜ける(hasMounts と同じ D18 の形)。
632
- * 読み手は必ずこのゲートを先に見て、真なら `recursionRegistry` を `!` で読む。
633
- * 必須メンバー(実装は `State` のみ)。`any` 型のテスト用モックがフィールドを持たなくても
634
- * 通るのは vitest が型検査をしないからで、その場合 `undefined === true` は偽なので再帰の
635
- * 経路に入らないだけ — 型としては必須。
636
- */
637
- readonly hasRecursion: boolean;
638
- /**
639
- * 再帰レジストリ(宣言が無ければ null。`hasRecursion === true` なら非 null)。registry.ts は
640
- * このファイルの IStateElement を参照するが、`import type` どうしなので実行時の循環にはならない。
641
- */
642
- readonly recursionRegistry: RecursionRegistry | null;
643
- setPathInfo(path: string, bindingType: BindingType, source?: PathInfoSource): void;
644
- addStaticDependency(parentPath: string, childPath: string): boolean;
645
- addDynamicDependency(fromPath: string, toPath: string): boolean;
646
- createStateAsync(mutability: Mutability, callback: (state: IStateProxy) => Promise<void>): Promise<void>;
647
- createState(mutability: Mutability, callback: (state: IStateProxy) => void): void;
648
- nextVersion(): number;
649
- setInitialState(state: Record<string, any>): void;
650
- }
651
-
652
- interface IPathInfo {
653
- readonly id: number;
654
- readonly path: string;
655
- readonly segments: string[];
656
- readonly lastSegment: string;
657
- readonly cumulativePaths: string[];
658
- readonly cumulativePathSet: Set<string>;
659
- readonly cumulativePathInfos: IPathInfo[];
660
- readonly cumulativePathInfoSet: Set<IPathInfo>;
661
- readonly parentPath: string | null;
662
- readonly parentPathInfo: IPathInfo | null;
663
- readonly wildcardPaths: string[];
664
- readonly wildcardPathSet: Set<string>;
665
- readonly indexByWildcardPath: Record<string, number>;
666
- readonly wildcardPathInfos: IPathInfo[];
667
- readonly wildcardPathInfoSet: Set<IPathInfo>;
668
- readonly wildcardParentPaths: string[];
669
- readonly wildcardParentPathSet: Set<string>;
670
- readonly wildcardParentPathInfos: IPathInfo[];
671
- readonly wildcardParentPathInfoSet: Set<IPathInfo>;
672
- readonly wildcardPositions: number[];
673
- readonly lastWildcardPath: string | null;
674
- readonly lastWildcardInfo: IPathInfo | null;
675
- readonly wildcardCount: number;
676
- }
677
- interface IStateAddress {
678
- readonly pathInfo: IPathInfo;
679
- readonly listIndex: IListIndex | null;
680
- readonly parentAddress: IStateAddress | null;
681
- }
682
- interface ITreePath {
683
- readonly stateElement: IStateElement;
684
- readonly pathInfo: IPathInfo;
685
- }
686
- interface IAbsoluteStateAddress {
687
- readonly absolutePathInfo: ITreePath;
688
- readonly listIndex: IListIndex | null;
689
- }
690
-
691
1
  type BindingType = 'text' | 'prop' | 'event' | 'for' | 'if' | 'elseif' | 'else' | 'radio' | 'checkbox' | 'spread';
2
+
692
3
  /**
693
- * 文法の段が読むフィルタ(名前と引数だけ。要件 D16)。実関数は束縛計画の段で
694
- * 登録簿から解決される(`core/filterRegistry.ts`)ので、パース結果はここで止まる。
695
- */
696
- interface IParsedFilter {
697
- readonly filterName: string;
698
- readonly args: string[];
699
- /**
700
- * 引数の型付きの値(要件 B9)。引用符の無い `true` / `false` / `null` / 数値は型付き、引用符付きは
701
- * 文字列のまま。`args` は引用符を外した原文(書式フィルタはこちらを読む)。組み立てた側が省略したら
702
- * `args` と同じ扱い。
703
- */
704
- readonly literals?: readonly unknown[];
705
- }
706
- /** 束縛計画の段で実関数まで解決したフィルタ */
707
- interface IFilterInfo extends IParsedFilter {
708
- readonly filterFn: FilterFn;
709
- }
710
- /**
711
- * バインディング式のパース結果(DOM 非依存の部分)。`@wcstack/state/parser` の
712
- * ParseBindTextResult がこれをそのまま公開するため、Node 等の DOM lib 型を
713
- * ここに足してはならない(足すなら IBindingInfo 側へ)。
714
- */
715
- interface IParsedBinding {
716
- readonly propName: string;
717
- readonly propSegments: string[];
718
- readonly propModifiers: string[];
719
- readonly statePathName: string;
720
- readonly statePathInfo: IPathInfo;
721
- readonly inFilters: IParsedFilter[];
722
- readonly outFilters: IParsedFilter[];
723
- readonly bindingType: BindingType;
724
- readonly uuid?: string | null;
725
- }
726
- /**
727
- * 束縛計画の段のバインディング。パース結果に DOM のノードと、**解決済みのフィルタ**が付く
728
- * (`bindings/getBindingInfos.ts` が登録簿から引く — 要件 D16)。
4
+ * The public types of @wcstack/state (the same names as 3.x). The engine's own classes stay
5
+ * internal: a page reaches `<wcs-state>` through `IStateElement`.
729
6
  */
730
- interface IBindingInfo extends IParsedBinding {
731
- readonly inFilters: IFilterInfo[];
732
- readonly outFilters: IFilterInfo[];
733
- readonly node: Node;
734
- readonly replaceNode: Node;
735
- }
736
7
 
737
- interface IState {
738
- [key: string]: any;
739
- }
740
- interface ITagNames {
741
- readonly state: string;
742
- readonly ssr: string;
743
- }
744
8
  interface IWritableTagNames {
745
9
  state?: string;
746
10
  ssr?: string;
747
11
  }
748
- interface IConfig {
749
- readonly bindAttributeName: string;
750
- readonly commentTextPrefix: string;
751
- readonly commentForPrefix: string;
752
- readonly commentIfPrefix: string;
753
- readonly commentElseIfPrefix: string;
754
- readonly commentElsePrefix: string;
755
- readonly tagNames: ITagNames;
756
- readonly locale: string;
757
- readonly debug: boolean;
758
- readonly enableMustache: boolean;
759
- /**
760
- * Enables direction-aware initial synchronization (`init=` / `sync=`).
761
- * Disabled by default while Phase 2 is evaluated against existing snapshots.
762
- */
763
- readonly enableDirectionalInitialSync: boolean;
764
- /**
765
- * Enables causal propagation tracking (transaction / edge provenance /
766
- * write receipts). Disabled by default while Phase 3 runs as a shadow of
767
- * the primitive same-value guard.
768
- */
769
- readonly enablePropagationContext: boolean;
770
- /**
771
- * Enables the opt-in dev-time contract analyzer (Phase 5b). When false
772
- * (default), `analyzeContract()` is a no-op with zero cost — runtime
773
- * behavior and allocation are unchanged. When true, it checks the actually
774
- * loaded `static wcBindable` declarations against a supplied sidecar
775
- * manifest and emits `contract:*` drift trace via the DevTools sink.
776
- */
777
- readonly enableContractAnalyzer: boolean;
778
- /**
779
- * 同値ガード(**既定 true**・標準的リアクティブ挙動・`setConfig({ sameValueGuard: false })` で opt-out 可)。
780
- * primitive 値の set で `Object.is` 同値なら更新を no-op にする
781
- * (enqueue / 依存 walk / DOM 適用 / $updatedCallback / DCC イベントを発火しない)。
782
- * 参照型(object/array)は in-place mutation 取りこぼし防止のため素通し。
783
- * 同値 set に副作用(同値時の $updatedCallback 等)を期待する場合は false にする。
784
- */
785
- readonly sameValueGuard: boolean;
786
- }
787
- /**
788
- * `$errorCallback(error, info)` の第 2 引数 — 適用に失敗したバインディングの識別情報。
789
- * 値と DOM は巻き戻されない(隔離規範)。作者はここで「どのバインディングが」を知り、
790
- * 自分の state にエラーを書いてページ内で受ける。
791
- */
792
- interface IBindingErrorInfo {
793
- /** バインドされた state パス(`data-wcs` に書かれた形。`items.*.name` などワイルドカードのまま) */
794
- readonly path: string;
795
- /** バインディング種別(text / property / attribute / class / style / for / if …) */
796
- readonly bindingType: BindingType;
797
- /** バインディングが付いたノード(テキストバインドでは Text ノード) */
798
- readonly node: Node;
799
- }
12
+ /** `bootstrapState(config)`: every option is optional (README "Configuration"). */
800
13
  interface IWritableConfig {
801
14
  bindAttributeName?: string;
802
- /** @deprecated Removed in 4.0, whose `bootstrapState` throws on it (3.5 warns `wcs/v4-migration`). */
803
- commentTextPrefix?: string;
804
15
  commentForPrefix?: string;
805
16
  commentIfPrefix?: string;
806
17
  commentElseIfPrefix?: string;
807
18
  commentElsePrefix?: string;
808
19
  tagNames?: IWritableTagNames;
809
20
  locale?: string;
810
- /** @deprecated Removed in 4.0, whose `bootstrapState` throws on it (3.5 warns `wcs/v4-migration`). */
811
- debug?: boolean;
812
- /** Moves to the state's `$behavior` in 4.0 (3.5 warns `wcs/v4-migration`); in 3.x, set it here. */
813
- enableMustache?: boolean;
814
- /** Moves to the state's `$behavior` in 4.0 (3.5 warns `wcs/v4-migration`); in 3.x, set it here. */
815
- enableDirectionalInitialSync?: boolean;
816
- /** @deprecated Removed in 4.0, whose `bootstrapState` throws on it (3.5 warns `wcs/v4-migration`). */
817
- enablePropagationContext?: boolean;
818
21
  enableContractAnalyzer?: boolean;
819
- /** Moves to the state's `$behavior` in 4.0 (3.5 warns `wcs/v4-migration`); in 3.x, set it here. */
820
- sameValueGuard?: boolean;
821
22
  }
822
-
823
- /**
824
- * 全機能を入れてから core を立ち上げる(従来の `bootstrapState()` と同じ挙動)。
825
- * install は要素の定義(connectedCallback が走り得る)より前に行う。いずれも冪等。
826
- */
827
- declare function bootstrapState(config?: IWritableConfig, registry?: CustomElementRegistry): void;
828
-
829
- declare function getConfig(): IConfig;
830
-
831
- /**
832
- * Trusted Types (`require-trusted-types-for 'script'`) 対応。正本は docs/csp.md §7。
833
- *
834
- * state が HTML sink に流すのは **状態の値**(`innerHTML: path` などのプロパティ
835
- * バインド)で、ユーザー入力が混ざり得る文字列そのもの。ここに identity policy を
836
- * 噛ませて通すのは TT の無効化と同義なので、state は自前の policy を作らない。
837
- * 利用側が sanitizer を持つ policy を注入したときだけ通し、無ければ従来どおり
838
- * ブラウザに弾かせる(ただし何を設定すれば直るかは必ず言う)。
839
- *
840
- * 注入口は全 @wcstack パッケージ共通のグローバルスロット。buildless(CDN 一発)でも
841
- * inline script 1 本で差し込める:
842
- *
843
- * ```js
844
- * globalThis[Symbol.for("wcstack.trustedTypes.policy")] =
845
- * trustedTypes.createPolicy("my-app", { createHTML: (s) => DOMPurify.sanitize(s) });
846
- * ```
847
- *
848
- * バンドラ経由なら `setTrustedTypesPolicy()` を使う。値は毎回スロットから読むので
849
- * 後から差し替えても効く(identity policy を作る router / worker 側だけは
850
- * `createPolicy` の重複を避けるため生成結果をシングルトンで保持する)。
851
- */
852
- interface IWcsTrustedTypesPolicy {
853
- createHTML?(input: string): unknown;
854
- createScriptURL?(input: string): unknown;
23
+ /** What `$errorCallback(error, info)` receives about the binding that failed. */
24
+ interface IBindingErrorInfo {
25
+ /** The bound state path as written in `data-wcs` (wildcards intact). */
26
+ readonly path: string;
27
+ /** The binding's type as the parser classifies it. */
28
+ readonly bindingType: BindingType;
29
+ /**
30
+ * The node the binding is on (the Text node for a text binding); null for a list no `for:`
31
+ * renders (one only `$getAll` or `$watch` keeps) that failed to read.
32
+ */
33
+ readonly node: Node | null;
34
+ }
35
+ /** `<wcs-state>` (README "IStateElement"). */
36
+ interface IStateElement extends HTMLElement {
37
+ /** Resolves when the state is loaded and the page bound — also when initialization fails. */
38
+ readonly initializePromise: Promise<void>;
39
+ /**
40
+ * Resolves once `connectedCallback` completed (`$connectedCallback` run); a root that fails to
41
+ * initialize rejects it, and so does one whose `$connectedCallback` rejects (its page is bound), a
42
+ * DCC definition and a component mount (`bind-component`) that fail — a volume that fails resolves it.
43
+ */
44
+ readonly connectedCallbackPromise: Promise<void>;
45
+ /** Runs `callback` with a state proxy; its writes are applied in the next drain. */
46
+ createState(mutability: "readonly" | "writable", callback: (state: Record<string, any>) => void): void;
47
+ /** `createState` whose callback may await; a readonly proxy stays readonly across its awaits. */
48
+ createStateAsync(mutability: "readonly" | "writable", callback: (state: Record<string, any>) => Promise<void>): Promise<void>;
49
+ /**
50
+ * Before initialization: the initial state. After: replaces the whole state and re-applies every
51
+ * binding — also on a root whose `$connectedCallback` rejected. Throws on a root that failed to
52
+ * initialize (#14), and on a loaded volume, component (`bind-component`) or DCC definition.
53
+ */
54
+ setInitialState(state: Record<string, any>): void;
855
55
  }
856
- /** 利用側が policy を差し込むグローバルスロット(全 @wcstack パッケージ共通)。 */
857
- declare const TRUSTED_TYPES_POLICY_SLOT: unique symbol;
858
- /**
859
- * 利用側が注入した policy を返す。state はここに identity policy をフォールバック
860
- * させない(それをやると TT を無効化することになる)。
861
- */
862
- declare function getTrustedTypesPolicy(): IWcsTrustedTypesPolicy | null;
863
- /** 利用側 policy を設定する(`null` で解除)。最初のバインド適用前に呼ぶこと。 */
864
- declare function setTrustedTypesPolicy(policy: IWcsTrustedTypesPolicy | null): void;
865
56
 
866
57
  /**
867
- * 指定された rootNode のバインディング初期化が完了するまで待機する Promise を返す。
58
+ * Resolves when the bindings of `root` are built — by any `<wcs-state>` in it now, whatever its
59
+ * `$connectedCallback` does then, as 3.x — and rejects, with the first failure, only when every one
60
+ * failed before building them. A stray one (a second root, #47; one that fails to load) changes
61
+ * nothing while another binds the root; one taken out of the page (or moved to another root) counts
62
+ * no more (a root replaced: the new one decides). With none in it — none ever, or only ones that left —
63
+ * it resolves at once: there is nothing to wait for (a page without state).
868
64
  */
869
- declare function getBindingsReady(rootNode: Node): Promise<void>;
870
-
65
+ declare function getBindingsReady(root: Node): Promise<void>;
871
66
  /**
872
- * Browser builds use the native HTMLElement. Headless runtimes receive an
873
- * inert base so the public module can be imported without installing DOM
874
- * globals; constructing components remains a browser-only operation.
67
+ * The base of the package's elements: HTMLElement, or — where there is none (Node without a DOM)
68
+ * — an inert class, so the entries can be imported headless (a tool reading the manifest, a
69
+ * server framework importing at the top level), as 3.x. Making an element stays a browser's.
875
70
  */
876
71
  declare const HTMLElementBase: typeof HTMLElement;
72
+ /**
73
+ * Waits for the bindings under `root` (3.x built them here; the new engine builds them when the
74
+ * root's `<wcs-state>` loads its state, so this only waits — the same as getBindingsReady).
75
+ */
76
+ declare const buildBindings: (root: Document | ShadowRoot) => Promise<void>;
877
77
 
878
78
  interface ISsrElement {
79
+ /** The @wcstack/state version that rendered the page. */
879
80
  readonly version: string;
880
- readonly stateData: IState;
81
+ /** The state's data the server rendered with. */
82
+ readonly stateData: Record<string, any>;
83
+ /** The page-level templates, by id. */
881
84
  readonly templates: Map<string, HTMLTemplateElement>;
85
+ /** Always empty: every binding is applied when the client adopts the server's DOM (3.x kept a value table here). */
882
86
  readonly hydrateProps: Record<string, Record<string, unknown>>;
883
- getTemplate(uuid: string): HTMLTemplateElement | null;
87
+ getTemplate(id: string): HTMLTemplateElement | null;
88
+ /** The snapshot is adoptable: the same major.minor as this build. */
884
89
  verifyVersion(): boolean;
885
90
  }
886
91
  declare class Ssr extends HTMLElementBase implements ISsrElement {
887
- private _stateData;
888
- private _templates;
889
- private _hydrateProps;
92
+ /** The first snapshot element under `root`, or null. */
93
+ static find(root: Node): ISsrElement | null;
890
94
  get version(): string;
891
- get stateData(): IState;
95
+ get stateData(): Record<string, any>;
892
96
  get templates(): Map<string, HTMLTemplateElement>;
893
97
  get hydrateProps(): Record<string, Record<string, unknown>>;
894
- getTemplate(uuid: string): HTMLTemplateElement | null;
895
- /**
896
- * サーバーの SSR バージョンとクライアントの state バージョンを検証する。
897
- * メジャー・マイナーバージョンが一致すればtrue。
898
- * version 属性がない場合は検証スキップ(true)。
899
- */
98
+ getTemplate(id: string): HTMLTemplateElement | null;
900
99
  verifyVersion(): boolean;
901
- setStateData(data: IState): void;
902
- setHydrateProps(props: Record<string, Record<string, unknown>>): void;
903
- private _loadStateData;
904
- private _loadTemplates;
905
- private _loadHydrateProps;
906
- static find(root: Node): ISsrElement | null;
907
- /**
908
- * stateData と構造テンプレート・プロパティから <wcs-ssr> の中身を構築する。
909
- * server パッケージの renderToString から呼ばれる。
910
- */
911
- /**
912
- * wcs-state 要素から $ プレフィックスや関数を除いたデータを抽出する。
913
- */
914
- static extractStateData(stateEl: Element): Record<string, any>;
915
- /**
916
- * @param scanRoot このスナップショットが属するツリー(既定は `ssrEl` の document)。
917
- * テンプレートと props はここから到達できるものだけを載せる — モジュール寿命の台帳に
918
- * 残った**別のレンダリング**の分を混ぜないため(リクエスト間のデータ漏れ)。
919
- */
920
- static buildContent(ssrEl: Element, stateData: Record<string, any>, scanRoot?: Node): void;
921
- /**
922
- * SSR ブロック境界コメント (@@wcs-*-start/end) を除去する
923
- */
924
- static removeBlockBoundaryComments(root: Node): void;
925
- /**
926
- * SSR の構造プレースホルダーコメント (@@wcs-for:uuid 等) を除去する
927
- */
928
- static removeStructuralComments(root: Node): void;
929
- /**
930
- * SSR テキストバインディングコメントを復元する。
931
- * <!--@@wcs-text-start:expression-->text<!--@@wcs-text-end:expression-->
932
- * → <!--@@: expression--> (バインディングシステムが認識する形式)
933
- *
934
- * The marker is read as an opaque expression, never as a path: since #373 the server writes the
935
- * binding's expression with its output filters (`price|toFixed(2)`, `items.*.price|toFixed(2)`; see
936
- * `textMarker`), before it the path alone. Both read the same way here, and so in every 3.x client.
937
- */
938
- static restoreTextBindings(root: Node): void;
939
- /**
940
- * SSR DOM をクリーンアップし、buildBindings が動作できる状態に戻す。
941
- * バージョン不一致時のフォールバック用。
942
- *
943
- * 1. SSR ブロック境界コメント間のレンダリング済みノードを除去
944
- * 2. SSR テキストバインディングを @@: 形式に復元
945
- * 3. プレースホルダーコメントを <wcs-ssr> 内のテンプレートで差し替え
946
- * 4. data-wcs-ssr-id 属性を除去
947
- * 5. <wcs-ssr> を除去
948
- */
949
- static cleanupDom(root: Document): void;
950
100
  }
951
101
 
952
- declare function buildBindings(root: Document | ShadowRoot): Promise<void>;
102
+ /**
103
+ * Page-wide configuration (`bootstrapState(config)`): how this page spells wcstack markup (the tag
104
+ * names, the binding attribute, the anchor comments — fixed before the first definition, the same
105
+ * on the server) and the locale default. How a state tree behaves is its own `$behavior` (engine.ts).
106
+ */
107
+ interface Config {
108
+ bindAttributeName: string;
109
+ /** The text of a `for` template's anchor comment. */
110
+ commentForPrefix: string;
111
+ /** The texts of an `if` / `elseif` / `else` chain's anchor comments. */
112
+ commentIfPrefix: string;
113
+ commentElseIfPrefix: string;
114
+ commentElsePrefix: string;
115
+ tagNames: {
116
+ state: string;
117
+ ssr: string;
118
+ };
119
+ locale: string;
120
+ /** Opt-in `analyzeContract()` (dev time); off, it returns at once. */
121
+ enableContractAnalyzer: boolean;
122
+ }
123
+ /** The current configuration (read-only view). */
124
+ declare const getConfig: () => Readonly<Config>;
125
+
126
+ /**
127
+ * Trusted Types for the HTML sinks (`html:`, `innerHTML:`, `outerHTML:`, `srcdoc:`).
128
+ * The policy lives on the same global slot as @wcstack/state, so a page that installed
129
+ * one for the current engine keeps working:
130
+ * globalThis[Symbol.for("wcstack.trustedTypes.policy")] = trustedTypes.createPolicy(…)
131
+ * No identity policy is ever created here — that would defeat the CSP.
132
+ */
133
+ interface TrustedTypesPolicy {
134
+ createHTML?(input: string): unknown;
135
+ }
136
+ declare const TRUSTED_TYPES_POLICY_SLOT: unique symbol;
137
+ declare function getTrustedTypesPolicy(): TrustedTypesPolicy | null;
138
+ declare function setTrustedTypesPolicy(policy: TrustedTypesPolicy | null): void;
953
139
 
954
140
  /**
955
141
  * defineState.ts
@@ -1106,10 +292,6 @@ interface WcsStateApi {
1106
292
  * 再評価させたくない場合に使う(該当行へ直接書き込む設計と組で用いる)。
1107
293
  */
1108
294
  $untracked<T>(fn: () => T): T;
1109
- /** @deprecated `$dependOn` の旧名(3.x の間は動き、4.0 で外れる — 要件 B12) */
1110
- $trackDependency(path: string): void;
1111
- /** @deprecated `$untracked` の旧名(3.x の間は動き、4.0 で外れる — 要件 B12) */
1112
- $untrackDependency<T>(fn: () => T): T;
1113
295
  /**
1114
296
  * 鍵付き購読: `path` の現在値が `key` に等しいかを返し、評価中のリスト行 getter を
1115
297
  * その鍵で購読する。`path` への書き込みは旧値・新値の鍵の行だけを再評価する
@@ -1188,7 +370,7 @@ type WcsThis<T> = T & WcsStateApi & WcsPathAccessor<T>;
1188
370
  *
1189
371
  * ### 基本的な使い方 (TypeScript)
1190
372
  * ```ts
1191
- * import { defineState } from '@wcstack/state';
373
+ * import { defineState } from '@wcstack/state/define';
1192
374
  *
1193
375
  * export default defineState({
1194
376
  * count: 0,
@@ -1207,7 +389,7 @@ type WcsThis<T> = T & WcsStateApi & WcsPathAccessor<T>;
1207
389
  *
1208
390
  * ### JavaScript (JSDoc)
1209
391
  * ```js
1210
- * import { defineState } from '@wcstack/state';
392
+ * import { defineState } from '@wcstack/state/define';
1211
393
  *
1212
394
  * export default defineState({
1213
395
  * count: 0,
@@ -1221,7 +403,7 @@ type WcsThis<T> = T & WcsStateApi & WcsPathAccessor<T>;
1221
403
  * ```html
1222
404
  * <wcs-state>
1223
405
  * <script type="module">
1224
- * import { defineState } from '@wcstack/state';
406
+ * import { defineState } from '@wcstack/state/define';
1225
407
  * export default defineState({
1226
408
  * count: 0,
1227
409
  * increment() { this.count++; }
@@ -1241,13 +423,14 @@ type WcsThis<T> = T & WcsStateApi & WcsPathAccessor<T>;
1241
423
  * // cleanup
1242
424
  * },
1243
425
  * $renderedCallback() {
1244
- * // called after the bindings are applied (old name: $updatedCallback)
426
+ * // called after the bindings are applied
1245
427
  * }
1246
428
  * });
1247
429
  * ```
1248
430
  */
1249
431
  declare function defineState<T extends Record<string, any>>(definition: T & ThisType<WcsThis<T>>): T;
1250
432
 
433
+ /** The package version: stamped into `<wcs-ssr>`, compared on hydration (major.minor), shown by DevTools. */
1251
434
  declare const VERSION: string;
1252
435
 
1253
436
  /**
@@ -1282,71 +465,37 @@ interface IFilterMeta {
1282
465
  /** 組み込みフィルタ名 → 構造化メタデータ。キー集合は builtinFilters と一致しなければならない。 */
1283
466
  declare const builtinFilterMeta: Record<string, IFilterMeta>;
1284
467
 
1285
- /**
1286
- * filters/filterAliases.ts — 組み込みフィルタの旧名 → 正式名(要件 B12・docs/state-3x-naming.ja.md V1〜V9)。
1287
- *
1288
- * 旧名は 3.x の間エイリアスとして残り、4.0 で外す(D4)。解決は登録簿(core/filterRegistry)が行い、
1289
- * 実装・引数の個数・メタデータは正式名だけが持つ。formats の install と manifest(tooling)の両方が読むので、
1290
- * 実装にもメタデータにも依存しない小さな表として独立させている。
1291
- */
1292
- declare const builtinFilterAliases: Readonly<Record<string, string>>;
1293
-
1294
- /**
1295
- * マニフェストのバージョン(構造を変えたら上げる)。
1296
- *
1297
- * 3.1 で `syntax.bindingTypes.explicitPropertyPrefix`、3.2 で `filterAliases`、
1298
- * 3.x の次で `declarationAliases` / `apiAliases` を足したので 2。
1299
- * 消費側(vscode-wcs)はまだこの定数を参照していないが、公開している以上ドリフトさせない。
1300
- */
468
+ /** The manifest's shape version (the same shape as 3.x). */
1301
469
  declare const WCS_MANIFEST_VERSION = 2;
470
+ /** Filter old names → canonical (3.2): removed in 4.0. */
471
+ declare const builtinFilterAliases: Readonly<Record<string, string>>;
1302
472
  interface IWcsManifest {
1303
473
  version: number;
1304
474
  syntax: {
1305
- /** バインド属性名(既定 data-wcs) */
1306
475
  bindAttribute: string;
1307
- /** タグ名(既定 wcs-state) */
1308
476
  tagName: string;
1309
- /** パス区切り(`.`) */
1310
477
  pathDelimiter: string;
1311
- /** ワイルドカード(`*`) */
1312
478
  wildcard: string;
1313
- /** バインディング構文 `[prop][#mod]: [path][|filter...]` の区切り文字 */
1314
479
  delimiters: {
1315
480
  binding: string;
1316
481
  propValue: string;
1317
482
  modifier: string;
1318
483
  filter: string;
1319
484
  };
1320
- /** 構造ディレクティブ(`<template data-wcs="for: ...">` 等) */
1321
485
  structuralDirectives: readonly string[];
1322
- /**
1323
- * 修飾子(`#` 後)の語彙。flags は値を取らない形(`#prevent`)、keyValue は
1324
- * `=` で値を取る形(`#init=element`)、eventNamePrefix は `on` + イベント名の形
1325
- * (`#onchange` — two-way / radio / checkbox のイベント名上書き。README「Modifiers」)。
1326
- * define.ts の定数が単一正本で、ランタイムの消費箇所も同じ定数に分岐する。
1327
- */
1328
486
  modifiers: {
1329
487
  flags: readonly string[];
1330
488
  keyValue: readonly string[];
1331
489
  eventNamePrefix: string;
1332
490
  };
1333
- /** リストインデックス参照名(`$1`..`$N`)。prefix + 1 始まり連番、maxDepth まで。 */
1334
491
  indexParam: {
1335
492
  prefix: string;
1336
493
  maxDepth: number;
1337
494
  };
1338
- /**
1339
- * bindingType 判別の語彙(parseBindTextsForElement の分岐と同一の定数から導出)。
1340
- * 判別順: else → spread → 構造ディレクティブ/radio/checkbox → eventToken・`on*`
1341
- * (event)→ prop。propNamespaces は左辺先頭セグメントの特殊 namespace で、
1342
- * apply 層のディスパッチキー集合との一致はテストが強制する。
1343
- * 既知の未収載: `radio` / `checkbox`(BindingType union のみが正本)。
1344
- */
1345
495
  bindingTypes: {
1346
496
  elseKeyword: string;
1347
497
  spread: string;
1348
498
  eventPropertyPrefix: string;
1349
- /** 左辺の先頭に付けると、名前が `on` で始まってもイベントにしない明示のプロパティ形(`.online:`、要件 B5) */
1350
499
  explicitPropertyPrefix: string;
1351
500
  propNamespaces: {
1352
501
  eventToken: string;
@@ -1357,176 +506,26 @@ interface IWcsManifest {
1357
506
  };
1358
507
  };
1359
508
  };
1360
- /** 組み込みフィルタ名(builtinFilters から自動導出=実装が正本) */
509
+ /** The built-in filter names: the core set, then the formats add-on's. */
1361
510
  filters: string[];
1362
- /** 組み込みフィルタの構造化メタデータ(説明・引数仕様・型)。vscode-wcs の手リスト撤去用。 */
1363
511
  filterMeta: Record<string, IFilterMeta>;
1364
- /** 組み込みフィルタの旧名 → 正式名(要件 B12)。旧名も解決するが、ツールは正式名を提案する */
1365
512
  filterAliases: Readonly<Record<string, string>>;
1366
- /**
1367
- * 宣言キーの旧名 → 正式名(要件 B12。`$updatedCallback` → `$renderedCallback`、
1368
- * `$streams` → `$stream`)。ランタイムは旧名も受けるが、ツールは正式名を提案する。
1369
- * `reservedLifecycle` / `reservedStateApi` は**正式名だけ**なので、旧名が予約かどうかは
1370
- * この表と併せて判断する
1371
- */
1372
513
  declarationAliases: Readonly<Record<string, string>>;
1373
- /** state API の旧名 → 正式名(`$trackDependency` → `$dependOn` 等、要件 B12) */
1374
514
  apiAliases: Readonly<Record<string, string>>;
1375
- /** 予約ライフサイクルフック名(正式名のみ。旧名は `declarationAliases` を見る) */
515
+ /** Reserved lifecycle hooks. */
1376
516
  reservedLifecycle: readonly string[];
1377
- /** 予約 state API(プロトコル系の `$` 名前空間。正式名のみ) */
517
+ /** Reserved state keys and `$` namespaces. */
1378
518
  reservedStateApi: readonly string[];
519
+ /** A state's `$behavior` options (4.0): each key, the type of its value and its value when left out. */
520
+ behaviorOptions: Readonly<Record<string, {
521
+ type: "boolean";
522
+ default: boolean;
523
+ }>>;
524
+ /** The add-on names `$features` and the root `<wcs-state features>` take (4.0). */
525
+ features: readonly string[];
1379
526
  }
1380
- /** 機械可読な単一正本を返す。vscode-wcs はこれを消費する想定。 */
1381
527
  declare function getWcsManifest(): IWcsManifest;
1382
528
 
1383
- /**
1384
- * devtools/types.ts
1385
- *
1386
- * DevTools Hook Protocol (docs/devtools-hook-protocol.md) の型定義。
1387
- *
1388
- * イベント payload はランタイム内部オブジェクト(IAbsoluteStateAddress /
1389
- * IBindingInfo 等)への生参照を含む(同一 realm・オーバーレイ前提、protocol 原則 4)。
1390
- * 消費者はこれらを変異してはならない。
1391
- */
1392
-
1393
- type DevtoolsEvent = {
1394
- readonly type: "state:element-registered";
1395
- readonly rootNode: Node;
1396
- readonly element: IStateElement;
1397
- } | {
1398
- readonly type: "state:element-unregistered";
1399
- readonly rootNode: Node;
1400
- readonly element: IStateElement;
1401
- } | {
1402
- readonly type: "state:write";
1403
- readonly absoluteAddress: IAbsoluteStateAddress;
1404
- readonly value: unknown;
1405
- /** same-value guard が既に取得していた場合のみ意味を持つ(protocol §4.2) */
1406
- readonly oldValue: unknown;
1407
- readonly hasOldValue: boolean;
1408
- } | {
1409
- readonly type: "state:update-batch";
1410
- readonly addresses: ReadonlySet<IAbsoluteStateAddress>;
1411
- } | {
1412
- readonly type: "state:binding-added";
1413
- readonly absoluteAddress: IAbsoluteStateAddress;
1414
- readonly binding: IBindingInfo;
1415
- } | {
1416
- readonly type: "state:binding-removed";
1417
- readonly absoluteAddress: IAbsoluteStateAddress;
1418
- readonly binding: IBindingInfo;
1419
- } | {
1420
- readonly type: "state:binding-cleared";
1421
- readonly absoluteAddress: IAbsoluteStateAddress;
1422
- } | {
1423
- readonly type: "state:token-emit";
1424
- readonly kind: "command" | "event";
1425
- readonly tokenName: string;
1426
- readonly args: readonly unknown[];
1427
- readonly subscriberCount: number;
1428
- /**
1429
- * 発火元ツリーの state 要素(protocol v2 追補 2026-09-05・additive)。
1430
- * registry(getOrCreate*Token)経由で作られた token だけが持つ — 直接生成された
1431
- * token や旧ランタイムの payload には無い(optional)。無い emit の実測は
1432
- * ツリー別に分けられないため、消費側は全ツリーの照会へ合算で残す。
1433
- */
1434
- readonly stateElement?: IStateElement;
1435
- } | {
1436
- readonly type: "state:watch-error";
1437
- /**
1438
- * throw 元。cur の評価(getter)とハンドラ本体では原因も直し方も違う。
1439
- * `$scan`(scan/scanReport.ts)は `evaluate`(source / 出力の読み)・`fold`(fold の throw・
1440
- * Promise の戻り値・接ぎ木で getter になった from)・`write`(出力の書き込み)を使う
1441
- */
1442
- readonly phase: "prime" | "evaluate" | "handler" | "fold" | "write";
1443
- /** `$watch` の宣言キー(ワイルドカードを含む生のパス)。`$scan` は `$scan.<出力名>` */
1444
- readonly path: string;
1445
- readonly error: unknown;
1446
- } | {
1447
- readonly type: "state:watch-chain-limit";
1448
- readonly maxDepth: number;
1449
- /** 打ち切ったバッチに載っていたアドレスのパス(報告用) */
1450
- readonly paths: readonly string[];
1451
- } | {
1452
- readonly type: "state:render-chain-limit";
1453
- readonly maxDepth: number;
1454
- /** 打ち切ったバッチに載っていたアドレスのパス(= 直前の描画の中で書かれたパス) */
1455
- readonly paths: readonly string[];
1456
- } | {
1457
- readonly type: "state:watch-fired";
1458
- /** `$watch` の宣言キー(ワイルドカードを含む生のパス) */
1459
- readonly path: string;
1460
- /**
1461
- * 発火元ツリーの state 要素(protocol v2 追補 2026-09-05・additive)。
1462
- * 複数ツリーが同名の watch パスを宣言するページで実測台帳をツリー別に
1463
- * 分けるための識別。旧ランタイムの payload には無い(optional)— 無い発火は
1464
- * 消費側が全ツリーの照会へ合算で残す。値を載せない契約(§4.3.1)は不変。
1465
- */
1466
- readonly stateElement?: IStateElement;
1467
- } | {
1468
- readonly type: "state:path-unresolved";
1469
- /** 書き手が書いた面。診断 code が binding / watch で変わる */
1470
- readonly source: "binding" | "watch" | "scan";
1471
- /** 宣言されたパス(ワイルドカードを含む生の文字列) */
1472
- readonly path: string;
1473
- /** 解決に失敗したセグメント */
1474
- readonly missingSegment: string;
1475
- } | {
1476
- readonly type: "state:binding-apply-error";
1477
- /** バインディングの state パス(ワイルドカードを含む生の文字列) */
1478
- readonly path: string;
1479
- readonly bindingType: string;
1480
- readonly error: unknown;
1481
- } | {
1482
- readonly type: "propagation:suppressed";
1483
- readonly reason: "confirmation" | "visited-edge";
1484
- readonly transactionId: number;
1485
- readonly edgeId: number;
1486
- readonly node: Node;
1487
- readonly member: string;
1488
- } | {
1489
- readonly type: "propagation:coalesced";
1490
- readonly absoluteAddress: IAbsoluteStateAddress;
1491
- readonly droppedTransactionId: number;
1492
- readonly winnerTransactionId: number;
1493
- } | {
1494
- readonly type: "propagation:hop-limit";
1495
- readonly absoluteAddress: IAbsoluteStateAddress;
1496
- readonly transactionId: number;
1497
- readonly hop: number;
1498
- } | {
1499
- readonly type: "contract:manifest-read";
1500
- readonly tag: string;
1501
- /** 実行時に該当タグが登録済みか(未登録なら drift の起点)。 */
1502
- readonly loaded: boolean;
1503
- } | {
1504
- readonly type: "contract:unsupported-extension";
1505
- readonly namespace: string;
1506
- } | {
1507
- readonly type: "contract:drift";
1508
- readonly reason: "component-not-loaded" | "missing-member" | "event-mismatch";
1509
- readonly tag: string;
1510
- readonly member?: string;
1511
- /** event-mismatch のとき: sidecar 宣言 event / live event。 */
1512
- readonly sidecarEvent?: string;
1513
- readonly liveEvent?: string;
1514
- };
1515
- /** contract analyzer(Phase 5b)が生成しうる event だけの狭い union(公開 API の戻り型)。 */
1516
- type ContractEvent = Extract<DevtoolsEvent, {
1517
- readonly type: "contract:manifest-read" | "contract:unsupported-extension" | "contract:drift";
1518
- }>;
1519
-
1520
- /**
1521
- * contract/types.ts
1522
- *
1523
- * Phase 5b(dev-time contract analyzer)が読む sidecar manifest の最小 subset。
1524
- * 完全な JSON-Schema subset 検証は CI 側(vscode-wcs の validator core)の責務であり、
1525
- * runtime analyzer は「実際に読み込まれた wcBindable 宣言との drift」照合に絞る。
1526
- *
1527
- * この型は vscode-wcs の `wcstack.types` を copy-distribution したもの(§14: ランタイム
1528
- * 依存を導入しない)。CI 側の全量型ではなく drift 照合に必要な形だけを持つ。
1529
- */
1530
529
  interface IContractObservable {
1531
530
  readonly event?: string;
1532
531
  }
@@ -1543,378 +542,35 @@ interface IContractManifest {
1543
542
  readonly [namespace: string]: unknown;
1544
543
  };
1545
544
  }
1546
-
1547
- /**
1548
- * contract/contractAnalyzer.ts
1549
- *
1550
- * Phase 5b(09-remediation-design.md §5b / §7.1 dev runtime / §6 contract trace)の
1551
- * opt-in dev-time analyzer。実際に登録済みの custom element の `static wcBindable`
1552
- * 宣言(= 実行時の正本)を、利用者が渡した sidecar manifest と突き合わせ、drift を
1553
- * DevTools trace(`contract:*`)へ流す。
1554
- *
1555
- * 完了条件「無効時の runtime 挙動・cost が不変」: `analyzeContract` は
1556
- * `config.enableContractAnalyzer` が false のとき即 return し、manifest を一切走査
1557
- * しない(hot path には一切フックしない — 純粋な on-demand API)。
1558
- *
1559
- * pure な core(`analyzeManifestContract`)は宣言解決と emit を注入で受けるためテスト可能。
1560
- */
1561
-
1562
- /**
1563
- * opt-in dev-time contract analysis。無効時はゼロコスト(即 return・manifest 非走査)。
1564
- * 有効時は live 宣言と manifest を突き合わせ、`contract:*` trace を返しつつ、DevTools
1565
- * sink が接続されていれば同時に流す。
1566
- */
545
+ type ContractEvent = {
546
+ /** One component's contract was read from the manifest; `loaded`: its tag is registered. */
547
+ readonly type: "contract:manifest-read";
548
+ readonly tag: string;
549
+ readonly loaded: boolean;
550
+ } | {
551
+ /** A manifest namespace the runtime does not interpret. */
552
+ readonly type: "contract:unsupported-extension";
553
+ readonly namespace: string;
554
+ } | {
555
+ /** The manifest and the live declaration disagree (the live one is authoritative). */
556
+ readonly type: "contract:drift";
557
+ readonly reason: "component-not-loaded" | "missing-member" | "event-mismatch";
558
+ readonly tag: string;
559
+ readonly member?: string;
560
+ readonly sidecarEvent?: string;
561
+ readonly liveEvent?: string;
562
+ };
1567
563
  declare function analyzeContract(manifest: IContractManifest): readonly ContractEvent[];
1568
564
 
1569
- declare class State extends HTMLElementBase implements IStateElement {
1570
- static hasConnectedCallbackPromise: boolean;
1571
- static getBindingsReady(rootNode: Node): Promise<void>;
1572
- /**
1573
- * `mount` の動的変更は未サポート(再マウントは非目標 — 設計書 §4-7)。
1574
- * 初期化済み要素での変更は無言で捨てず warn で知らせる。初期化前の属性設定
1575
- * (パース時・接続前の setAttribute)は正規の使い方なので黙る。
1576
- * `name` は connectedCallback 冒頭で fail-fast 済みなので観測しない。
1577
- */
1578
- static get observedAttributes(): string[];
1579
- private __state;
1580
- private _hasUpdatedCallback;
1581
- /** $errorCallback の有無(_hasUpdatedCallback と同じく state セット時に確定。ルートのみ) */
1582
- private _hasErrorCallback;
1583
- /** enable-ssr のスナップショットから初期化された(D14: ボリュームはデータを採用する) */
1584
- private _hydratedFromSsr;
1585
- private _crossRowListPaths;
1586
- private _indexDependentGetterPaths;
1587
- private _initialized;
1588
- /**
1589
- * 初期化(`_initialize`)が失敗した(#257)。`_initialized` の裏返しではない —
1590
- * 「まだ初期化していない」と「もう初期化できない」を取り違えると、復旧不能の
1591
- * 要素に `setInitialState` が効いたように見える。真にするのは
1592
- * `_failInitializeLoudly` だけ。
1593
- */
1594
- private _initializeFailed;
1595
- /**
1596
- * この接続サイクルの失敗は**もう着地した**(#257)。設定エラーの fail-fast
1597
- * (`_failInitialization` と `initializeMountScope` の catch)は自分で promise を
1598
- * 解決してから raise する — connectedCallbackPromise を**解決**する側のクラスなので、
1599
- * 下の loud な着地(reject + 診断)に載せ替えると意味論が変わる。接続ごとに畳む。
1600
- */
1601
- private _initializationLanded;
1602
- private _initializePromise;
1603
- private _resolveInitialize;
1604
- private _connectedCallbackPromise;
1605
- private _resolveConnectedCallback;
1606
- private _rejectConnectedCallback;
1607
- private _loadingPromise;
1608
- private _resolveLoading;
1609
- private _setStatePromise;
1610
- private _resolveSetState;
1611
- private _listPaths;
1612
- private _listKeys;
1613
- private _recursionRegistry;
1614
- private _elementPaths;
1615
- private _getterPaths;
1616
- private _setterPaths;
1617
- private _loopContextStack;
1618
- private _dynamicDependency;
1619
- private _staticDependency;
1620
- private _pathSet;
1621
- /**
1622
- * state の世代(issue #258 の X10)。`_state` の差し替えごとに 1 つ進み、キャッシュ項目の
1623
- * 印になる(cache/types.ts の `generation`)。`_version`(更新サイクルの番号)とは別の
1624
- * カウンタで、増える条件が違う — 再セットは世代だけを進める
1625
- * (`__tests__/integration.stateGenerationReset.test.ts` の
1626
- * 「再セットは世代だけを進め、version は動かさない」が固定する)。
1627
- */
1628
- private _stateGeneration;
1629
- /**
1630
- * この要素が受け取った `setPathInfo` の台帳(issue #258 の X7)。パス → 種別と呼び出し元。
1631
- *
1632
- * `_pathSet` / `_listPaths` / `_elementPaths` は再セットでクリアされるが、それらを登録した
1633
- * バインドは生き残る(再セットは DOM を作り直さない)。台帳が空のままだと依存ウォークが
1634
- * `items` をリストとして展開できず、全リスト書き込みが「非リストのアドレスにワイルドカードを
1635
- * 展開できない」で恒久的に throw する(値と DOM は追従するが、書き込みのたびに投げ続ける)。
1636
- * クリアのあと、この台帳から作り直す(`_rebuildPathInfo`)。
1637
- *
1638
- * `source === "internal"`(再帰の生成アクセサ・ボリュームのツリーアクセサ)は載せない。
1639
- * あれらは生やした機構が新しい世代で登録し直す(recursion/registry.ts の `_define`)。
1640
- *
1641
- * `bound` はバインドがいちどでも登録したか(#270)。作り直しで存在検査をやり直すのはバインドの
1642
- * パスだけ — `$watch` / `$scan` の登録は前の世代の宣言の残骸でもあり、今の世代の宣言は
1643
- * 作り直しの後で自分の検査をする(`processWatchDeclaration` / `registerScans`)。残骸まで
1644
- * 検査すると、新しい宣言から外したパスを「存在しない」と誤って報告する。
1645
- */
1646
- private _pathRegistrations;
1647
- /**
1648
- * 切断中の再セットで適用し直せなかったトップレベルのパス(#267)。再適用には rootNode が要るので、
1649
- * 再接続で `reapplyStateBindings` に渡す。切断中に何度入れ直しても和集合で持つ
1650
- * (前の世代にしか無いキーのバインドも失敗として報告させるため)。
1651
- */
1652
- private _pendingReapplyPaths;
1653
- /**
1654
- * これまでのどの世代かで再帰レジストリが実体化した具体パス(`nodes.*.total` 等)の累積。
1655
- * 再セットのたびに `forgetGenerated` の戻り値を足し、`_rebuildPathInfo` の除外に使う。
1656
- *
1657
- * 除外は**世代を跨いで累積する**。読みを挟まない連続した再セットでも、生成アクセサの具体パスを
1658
- * 指す静的辺(`nodes.*` → `nodes.*.total`)が戻らないことは、
1659
- * `__tests__/integration.stateGenerationReset.test.ts` の
1660
- * 「読みを挟まない 3 連続の再セットで静的辺が戻らない」が固定する。
1661
- */
1662
- private _generatedPaths;
1663
- private _watchPaths;
1664
- private _scanPaths;
1665
- private _version;
1666
- private _rootNode;
1667
- private _boundComponent;
1668
- private _boundComponentStateProp;
1669
- private _hasMounts;
1670
- private _hasGraftedVolumes;
1671
- /** 読み書き境界の hook(設計案 H1)。宣言が要求する機能の分だけ付く */
1672
- private _addressHooks;
1673
- private _bindableEventMap;
1674
- private _commandTokenNames;
1675
- private _eventTokenNames;
1676
- private _treeless;
1677
- private _connectGeneration;
1678
- constructor();
1679
- private get _state();
1680
- private set _state(value);
1681
- attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void;
1682
- private _loadFromSsrElement;
1683
- /**
1684
- * state / src / json / inner <script> / API set のソース解決(_initialize とボリュームで共用)。
1685
- *
1686
- * A load failure is not wrapped, here or in the loaders: what was thrown propagates as is —
1687
- * the SyntaxError of `JSON.parse` (`state=` / `json=`), the `import()` rejection or the
1688
- * module's own throw (`src="*.js"`), the inline-script loader's Error (the import failure is
1689
- * its `cause`), the unsupported-extension error, or a non-Error value. On a root,
1690
- * `_failInitializeLoudly` logs it under the element's "failed to initialize" line and rejects
1691
- * connectedCallbackPromise with that same value (the README contract); on a volume,
1692
- * volumeLifecycle logs it under its "failed to load" line. The old wrappers
1693
- * (`Failed to initialize state: ${e}` here, `Failed to load script file` /
1694
- * `Failed to parse JSON from script element` in the loaders) were new Errors that kept the
1695
- * original only as text, losing its type, stack and cause.
1696
- *
1697
- * Two sources do not fail at all in 3.x (README): `src="*.json"` that cannot be fetched or
1698
- * parsed, and `state=` naming no JSON script. Both log and start with an empty state.
1699
- */
1700
- private _loadStateFromSource;
1701
- /**
1702
- * 初回マウントのロードと登録。戻り値は「この接続で初期化を**完了**したか」で、
1703
- * `false` は失敗ではなく**中断**(ロード中に要素が剥がされた — 下の注記)。
1704
- */
1705
- private _initialize;
1706
- /**
1707
- * 設定エラーでの fail-fast。initializePromise 等を解決してから raise する —
1708
- * 未解決のまま投げると waitForStateInitialize(ホストの buildBindings)が
1709
- * この要素を待ち続け、**ページ全体が無言でウェッジする**(1 つの設定ミスが
1710
- * 無関係なバインディングまで道連れにする)。エラー自体は unhandled rejection
1711
- * として loud に残る。
1712
- */
1713
- private _failInitialization;
1714
- /**
1715
- * `_initialize` の失敗の着地(#257)。旧挙動は「throw が connectedCallback の外へ
1716
- * 出るだけ」で、`_initializePromise` も `_connectedCallbackPromise` も永久に未解決の
1717
- * まま残り、作者が受け取るのは診断ではなく無言のハングだった。載るのは
1718
- * `_initialize` が投げうるもの全部 — `_state` セッタの宣言検証($recursion /
1719
- * $commandTokens / $eventTokens / $on / $streams / $listKeys / $watch)、
1720
- * `_loadStateFromSource` のロード失敗(src の拡張子・json のパース・内包スクリプト・
1721
- * 外部モジュール)、SSR データの merge、そして `setStateElement` の
1722
- * 「1 rootNode 1 ツリー」違反(**別の**要素が 2 本目に来た形 — 同じ要素の再登録は
1723
- * 冪等なので、ロード中の remove → append はここへ来ない)。
1724
- *
1725
- * 載**らない**もの: ロード中に要素が剥がされた形。作者のミスが 1 つも無いので
1726
- * 初期化失敗ではなく中断として扱う(`_initialize` が `false` を返す)。
1727
- *
1728
- * もう 1 つ載らないのがボリューム(`mount=`)の失敗。`_initializeVolume` の catch が
1729
- * 3 つの promise(initialize / loading / connectedCallback)を自分で解決してから raise し、
1730
- * `connectedCallback` のボリューム分岐はそれを包まないので、ボリュームはこの着地に
1731
- * 載らず connectedCallbackPromise を**拒否しない**。自前の報告が出るかどうかは失敗の
1732
- * 種類による。報告が無い形では、逃げ方は `name=`(`_failInitialization` の注記)と
1733
- * 同じで、throw はカスタム要素リアクションが捨てる戻り Promise へ出ていく
1734
- * (ブラウザのコンソールには "Uncaught (in promise)" として残るが、promise を待つ側
1735
- * = renderToString・mount・テストレシピには届かない)。失敗箇所ごとの正確な挙動は
1736
- * `__tests__/integration.initFailureDiagnostics.test.ts` が固定している。挙動はこの
1737
- * PR では変えない(枠の寿命は別 Issue)。
1738
- *
1739
- * `connectedCallback` が `_initialize` より前に await する 2 つ
1740
- * (DCC の接続 — dcc/dccLifecycle.ts が内部面の `failInitializeLoudly` で載せる — と、
1741
- * `bind-component` の preparing)の raise も同じ着地に載る。
1742
- * 特に「初期化に失敗した要素の再接続」は `bindWebComponent` → `setInitialState` の
1743
- * 復旧不能 raise でそこへ来るので、包まないと診断ゼロで素通りする。
1744
- *
1745
- * `_failInitialization`(設定エラーの fail-fast)との違いは 1 つ:
1746
- * **connectedCallbackPromise を reject する**。ここまで来た要素は state を 1 つも
1747
- * 持たない = このツリーは存在しない。resolve すると、それを待つ消費者
1748
- * (@wcstack/server の renderToString・@wcstack/testing の mount・README の
1749
- * テストレシピ)に「準備完了」と嘘をつく。下の SSR 経路(_rejectConnectedCallback)と
1750
- * 同じ規範で、そちらと同じく**元のエラーをそのまま**投げ直す。
1751
- *
1752
- * `initializePromise` は従来どおり**解決**する(reject しない)。
1753
- * `waitForStateInitialize` はページ中の全 `<wcs-state>` の initializePromise を
1754
- * `Promise.all` で待つので、reject にすると 1 要素の設定ミスが無関係な
1755
- * バインディングまで道連れになる(_failInitialization の注記と同じ理由)。
1756
- *
1757
- * 後始末はしない: `_initialized` を立てないので `disconnectedCallback` は初期化前
1758
- * ガードで抜ける。`$listKeys` / `$watch` のようにセッタの後半で落ちた形では
1759
- * `$on` の購読と stream registry が残るが、この要素は復旧不能(setInitialState が
1760
- * throw する)なので、残骸は要素ごと捨てる前提で放置する。
1761
- *
1762
- * `ownsTree` が false の着地は、この要素だけを失敗させてルートに触らない。`mount=` の
1763
- * readiness barrier(要件 D23)が使う: ボリュームはツリーの持ち主ではなく、ルートより先に
1764
- * 接続したボリュームでは rootNode にまだ誰も居ないので、既定の着地だとまだ来ていないルートの
1765
- * ノードを利用不能と印付けし、保留中の他のボリュームまで落としてしまう。
1766
- */
1767
- private _failInitializeLoudly;
1768
- private _callStateConnectedCallback;
1769
- private _callStateDisconnectedCallback;
1770
- connectedCallback(): Promise<void>;
1771
- disconnectedCallback(): void;
1772
- get initialized(): boolean;
1773
- /**
1774
- * ライフサイクル機能(core/lifecycleHooks.ts、設計案 H3)へ開く内部面。接続を引き取った機能が
1775
- * 要素の初期化を所有するために要る最小限。
1776
- */
1777
- get connectedRootNode(): Node | null;
1778
- clearConnectedRootNode(): void;
1779
- markInitialized(): void;
1780
- settleInitialization(): void;
1781
- loadStateFromSource(): Promise<Record<string, any>>;
1782
- markTreeless(): void;
1783
- /** 初期化失敗の着地(`_failInitializeLoudly`)。接続を引き取った機能が自分の失敗を載せる */
1784
- failInitializeLoudly(error: unknown): never;
1785
- get connectGeneration(): number;
1786
- setWatchPaths(paths: ReadonlySet<string> | null): void;
1787
- setScanPaths(paths: ReadonlySet<string> | null): void;
1788
- /** 設定エラーの着地(`_failInitialization` の raise を除いた部分)。引き取った機能が使う */
1789
- landInitialization(): void;
1790
- setRecursionRegistry(registry: RecursionRegistry | null): void;
1791
- addGeneratedPath(path: string): void;
1792
- setBoundComponent(component: Element | null, stateProp: string | null): void;
1793
- get initializePromise(): Promise<void>;
1794
- get connectedCallbackPromise(): Promise<void>;
1795
- get listPaths(): Set<string>;
1796
- get listKeys(): ListKeyMap | null;
1797
- get hasRecursion(): boolean;
1798
- get recursionRegistry(): RecursionRegistry | null;
1799
- get watchPaths(): ReadonlySet<string> | null;
1800
- get scanPaths(): ReadonlySet<string> | null;
1801
- get elementPaths(): Set<string>;
1802
- /**
1803
- * ボリューム(webComponent/volume.ts)のアクセサ登録: ツリーパスをキーにした
1804
- * quoted-path アクセサを state オブジェクトに定義し、getter / setter 台帳と
1805
- * 依存グラフに載せる。ルートのワイルドカード getter(`"children.*.label"`)と
1806
- * 同じ機構に乗るので、評価は pushAddress 下・依存はグラフに載る。
1807
- */
1808
- /** ボリュームの watch パスをホットパス用ゲート(watchPaths)へ合流させる。 */
1809
- addVolumeWatchPaths(paths: ReadonlySet<string>): void;
1810
- /** ボリュームの $listKeys(接頭辞翻訳済み)をルートの表へ合流させる。衝突は設定ミス。 */
1811
- mergeVolumeListKeys(entries: ReadonlyMap<string, ListKeySpec>): void;
1812
- /** ボリュームが $updatedCallback を持つとき、収集ゲートを開ける(apply/applyChange.ts)。 */
1813
- enableUpdatedCallback(): void;
1814
- /** enable-ssr スナップショットから初期化されたか(D14 — webComponent/volume.ts が読む)。 */
1815
- get hydratedFromSsr(): boolean;
1816
- addListPath(path: string): void;
1817
- findStateDescriptor(path: string): PropertyDescriptor | undefined;
1818
- defineTreeAccessor(path: string, descriptor: PropertyDescriptor): void;
1819
- get getterPaths(): Set<string>;
1820
- get setterPaths(): Set<string>;
1821
- get loopContextStack(): ILoopContextStack;
1822
- get dynamicDependency(): Map<string, string[]>;
1823
- get staticDependency(): Map<string, string[]>;
1824
- get version(): number;
1825
- /** state の世代(キャッシュ項目の印の正本 — cache/types.ts の `generation`)。 */
1826
- get stateGeneration(): number;
1827
- get rootNode(): Node;
1828
- get boundComponentStateProp(): string | null;
1829
- get hasMounts(): boolean;
1830
- /** 唯一の呼び手は webComponent/mount.ts の registerMountRecord(Phase 2)。 */
1831
- markHasMounts(): void;
1832
- get hasGraftedVolumes(): boolean;
1833
- get addressHooks(): IAttachedHooks | null;
1834
- /** 宣言 `declaration` が要求する機能 `feature` の hook をこの state に付ける(未 install なら throw、D13) */
1835
- attachAddressHooks(feature: string, declaration: string): void;
1836
- /** 唯一の呼び手は webComponent/volume.ts の graftVolume(D22 後段のガードが読む)。 */
1837
- markHasGraftedVolumes(): void;
1838
- /** ボリュームがこのルートに予約された(接ぎ木前でも、予約下の読みは undefined が正 — D22) */
1839
- markHasVolume(): void;
1840
- /** スコープ機能(マウント・ボリューム)の hook をこの state に付ける(冪等) */
1841
- private _attachScopeHooks;
1842
- get bindableEventMap(): Record<string, string>;
1843
- get commandTokenNames(): ReadonlySet<string>;
1844
- get eventTokenNames(): ReadonlySet<string>;
1845
- setBindableEventMap(map: Record<string, string>): void;
1846
- private _addDependency;
1847
- /**
1848
- * source, target
1849
- *
1850
- * products.*.price => products.*.tax
1851
- * get "products.*.tax"() { return this["products.*.price"] * 0.1; }
1852
- *
1853
- * products.*.price => products.summary
1854
- * get "products.summary"() { return this.$getAll("products.*.price", []).reduce(sum); }
1855
- *
1856
- * categories.*.name => categories.*.products.*.categoryName
1857
- * get "categories.*.products.*.categoryName"() { return this["categories.*.name"]; }
1858
- *
1859
- * @param sourcePath
1860
- * @param targetPath
1861
- */
1862
- addDynamicDependency(sourcePath: string, targetPath: string): boolean;
1863
- /**
1864
- * source, target
1865
- * products => products.*
1866
- * products.* => products.*.price
1867
- * products.* => products.*.name
1868
- *
1869
- * @param sourcePath
1870
- * @param targetPath
1871
- */
1872
- addStaticDependency(sourcePath: string, targetPath: string): boolean;
1873
- setPathInfo(path: string, bindingType: BindingType, source?: PathInfoSource): void;
1874
- /**
1875
- * 再セットで消した経路情報を、生き残ったバインドの登録から作り直す(issue #258 の X7)。
1876
- *
1877
- * `_pathSet.clear()` は残す。あのクリアには、`forgetGeneration` が外した静的辺を「行が
1878
- * 作り直されたときに登録し直させる」自己修復が乗っている(辺が戻ることは
1879
- * `__tests__/integration.stateGenerationReset.test.ts` の
1880
- * 「静的な辺 nodes.* → nodes.*.total が戻る」が固定する)。消したうえで、生きているバインド
1881
- * ぶんだけ `setPathInfo` をやり直す — `$recursion` のアンカーで既に同じことをしている手口を、
1882
- * バインド全体へ広げたもの。
1883
- *
1884
- * `_generatedPaths`(これまでの世代の生成アクセサの具体パス)は張り直さない。行バインドが
1885
- * 名指していても、新しい世代ではまだ実体化されていないため(recursion/generation.ts)。読みが
1886
- * 実体化したときに `defineTreeAccessor` が登録し直す。
1887
- *
1888
- * 作り直すのはバインドが登録したパスだけ(`_pathRegistrations` の `bound`・#270)。`$watch` /
1889
- * `$scan` だけの登録は飛ばす — 作り直しの後で今の世代の宣言が自分で登録し直し、そこで存在も
1890
- * 検査される。ここで `_pathSet` に入れてしまうと、宣言側の `setPathInfo` が `_pathSet.has` で
1891
- * 素通りし、両方の世代で宣言し続けたパスが新しい state で消えても報告されない。
1892
- *
1893
- * 反復中に `setPathInfo` が台帳へ書き戻す(既存キーの上書きのみで新キーは増えない)ので、
1894
- * 誤解を避けるためスナップショットを取ってから回す。
1895
- */
1896
- private _rebuildPathInfo;
1897
- private _createState;
1898
- createStateAsync(mutability: Mutability, callback: (state: IStateProxy) => Promise<void>): Promise<void>;
1899
- createState(mutability: Mutability, callback: (state: IStateProxy) => void): void;
1900
- nextVersion(): number;
1901
- get hasUpdatedCallback(): boolean;
1902
- get hasErrorCallback(): boolean;
1903
- get crossRowListPaths(): ReadonlySet<string>;
1904
- addCrossRowListPath(path: string): void;
1905
- get indexDependentGetterPaths(): ReadonlySet<string>;
1906
- addIndexDependentGetterPath(path: string): void;
1907
- setInitialState(state: Record<string, any>): void;
1908
- /** 確立済みのバインドを今の世代で適用し直す(#267)。行のバインドは経路情報の台帳のパスから引く。 */
1909
- private _reapplyBindings;
1910
- }
565
+ /** Installs every add-on, applies `config` and registers `<wcs-state>` (in `registry`, the global one by default). */
566
+ declare function bootstrapState(config?: IWritableConfig, registry?: CustomElementRegistry): void;
1911
567
 
1912
568
  declare global {
1913
569
  interface HTMLElementTagNameMap {
1914
- "wcs-state": State;
570
+ "wcs-state": IStateElement;
1915
571
  "wcs-ssr": Ssr;
1916
572
  }
1917
573
  }
1918
574
 
1919
575
  export { Ssr, TRUSTED_TYPES_POLICY_SLOT, VERSION, WCS_MANIFEST_VERSION, analyzeContract, bootstrapState, buildBindings, builtinFilterAliases, builtinFilterMeta, defineState, getBindingsReady, getConfig, getTrustedTypesPolicy, getWcsManifest, setTrustedTypesPolicy };
1920
- export type { ContractEvent, FilterArgType, FilterResultType, IBindingErrorInfo, IContractManifest, IFilterMeta, ISsrElement, IWcsManifest, IWcsTrustedTypesPolicy, IWritableConfig, IWritableTagNames, WcsPathValue, WcsPaths, WcsStateApi, WcsThis };
576
+ export type { ContractEvent, FilterArgType, FilterResultType, IBindingErrorInfo, IContractManifest, IFilterMeta, ISsrElement, IStateElement, IWcsManifest, TrustedTypesPolicy as IWcsTrustedTypesPolicy, IWritableConfig, IWritableTagNames, WcsPathValue, WcsPaths, WcsStateApi, WcsThis };