@wcstack/state 1.33.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -91,21 +91,12 @@ interface IStateProxy extends IState {
91
91
  type Mutability = "readonly" | "writable";
92
92
 
93
93
  interface IStateElement {
94
- readonly name: string;
95
94
  /**
96
95
  * state のロードが完了しているか。`initializePromise` の同期版で、
97
96
  * DCC のアクセサが「今すぐ読み書きしてよいか」を判断するのに使う。
98
97
  * optional なのはテスト用モック互換のため(undefined は「不明=未初期化扱い」)。
99
98
  */
100
99
  readonly initialized?: boolean;
101
- /**
102
- * この state element が今使えるか(= 接続済みで rootNode を保持しているか)。
103
- * `createState` は rootNode を要求するので、false のときに呼ぶと raiseError する。
104
- * 台帳に載っていること(登録済み)と使えることは別で、要素をキーにした台帳には
105
- * 切断済みの state element が残る窓がある(§1.9)。
106
- * optional なのはテスト用モック互換のため(undefined は「不明=使える扱い」)。
107
- */
108
- readonly hasRootNode?: boolean;
109
100
  readonly initializePromise: Promise<void>;
110
101
  readonly connectedCallbackPromise: Promise<void>;
111
102
  readonly listPaths: Set<string>;
@@ -122,22 +113,34 @@ interface IStateElement {
122
113
  * `bind-component` で束ねられているコンポーネント要素(親スコープ側のノード)。
123
114
  * マッピング規則の引き当てに使う。optional なのはテスト用モック互換のため。
124
115
  */
125
- readonly boundComponent?: Element | null;
126
116
  /**
127
117
  * この state の実体が innerState proxy(= 値の正本が親スコープの state にある
128
118
  * mapped な `bind-component`)か。真のときだけ越境アドレスの受け渡しと
129
119
  * リストパスの外向き伝播が働く(§1.8)。
130
120
  * optional なのはテスト用モック互換のため(undefined は plain 扱い)。
131
121
  */
132
- readonly hasMappedComponentState?: boolean;
133
- markComponentStateMapped?(): void;
122
+ /**
123
+ * この state element にマウント(Phase 2 の単一ツリー — webComponent/mount.ts)が
124
+ * 1 つでも登録されているか。偽のとき getByAddress / isCacheable / `$n` 補正は
125
+ * boolean 判定 1 個でオーバーレイ経路を抜ける(設計書 D18)。
126
+ * optional なのはテスト用モック互換のため(undefined は「マウント無し」扱い)。
127
+ */
128
+ readonly hasMounts?: boolean;
129
+ markHasMounts?(): void;
130
+ /**
131
+ * この state element に接ぎ木済みのボリューム(`mount=` — webComponent/volume.ts)が
132
+ * 1 つでもあるか。偽のとき setByAddress の D22 後段ガード(マウントポイントを含む
133
+ * 親の丸ごと書き検査)は boolean 判定 1 個で抜ける(設計書 D18 と同じ形)。
134
+ * optional なのはテスト用モック互換のため(undefined は「ボリューム無し」扱い)。
135
+ */
136
+ readonly hasGraftedVolumes?: boolean;
137
+ markHasGraftedVolumes?(): void;
134
138
  /**
135
139
  * この state 要素に束ねられた(`setPathInfo` を通った)パスの集合。丸ごとマウント
136
140
  * (ルート規則)の親→子通知が「登録済みパス全部を読み直せ」を組み立てるのに使う
137
141
  * (webComponent/rootReloadPaths.ts)。
138
142
  * optional なのはテスト用モック互換のため(undefined は「登録なし」扱い)。
139
143
  */
140
- readonly boundPaths?: ReadonlySet<string>;
141
144
  /**
142
145
  * DCC の `$bindables` から生成した「パス → 変更イベント名」表。
143
146
  * 唯一の書き手は defineDCC で、読み手は setByAddress。
@@ -191,13 +194,20 @@ interface IStateElement {
191
194
  * `source` は存在検査の診断 code と適用範囲を決める(pathDiagnostics.ts)。
192
195
  * 省略時は `"binding"`(テスト用モック互換のため optional)。
193
196
  */
197
+ /** ボリュームの宣言面の合流(webComponent/volume.ts 専用・実装は State のみ) */
198
+ addVolumeWatchPaths?(paths: ReadonlySet<string>): void;
199
+ mergeVolumeListKeys?(entries: ReadonlyMap<string, ListKeySpec>): void;
200
+ enableUpdatedCallback?(): void;
201
+ /** enable-ssr スナップショットから初期化されたか(D14)。 */
202
+ readonly hydratedFromSsr?: boolean;
203
+ /** ボリュームのアクセサ登録(webComponent/volume.ts 専用) */
204
+ defineTreeAccessor(path: string, descriptor: PropertyDescriptor): void;
194
205
  setPathInfo(path: string, bindingType: BindingType, source?: PathInfoSource): void;
195
206
  addStaticDependency(parentPath: string, childPath: string): boolean;
196
207
  addDynamicDependency(fromPath: string, toPath: string): boolean;
197
208
  createStateAsync(mutability: Mutability, callback: (state: IStateProxy) => Promise<void>): Promise<void>;
198
209
  createState(mutability: Mutability, callback: (state: IStateProxy) => void): void;
199
210
  nextVersion(): number;
200
- bindProperty(prop: string, desc: PropertyDescriptor): void;
201
211
  setInitialState(state: Record<string, any>): void;
202
212
  }
203
213
 
@@ -232,7 +242,6 @@ interface IStateAddress {
232
242
  readonly parentAddress: IStateAddress | null;
233
243
  }
234
244
  interface IAbsolutePathInfo {
235
- readonly stateName: string;
236
245
  readonly stateElement: IStateElement;
237
246
  readonly pathInfo: IPathInfo;
238
247
  readonly parentAbsolutePathInfo: IAbsolutePathInfo | null;
@@ -276,7 +285,6 @@ interface IParsedBinding {
276
285
  readonly propModifiers: string[];
277
286
  readonly statePathName: string;
278
287
  readonly statePathInfo: IPathInfo;
279
- readonly stateName: string;
280
288
  readonly inFilters: IFilterInfo[];
281
289
  readonly outFilters: IFilterInfo[];
282
290
  readonly bindingType: BindingType;
@@ -371,7 +379,6 @@ declare function getBindingsReady(rootNode: Node): Promise<void>;
371
379
  declare const HTMLElementBase: typeof HTMLElement;
372
380
 
373
381
  interface ISsrElement {
374
- readonly name: string;
375
382
  readonly version: string;
376
383
  readonly stateData: IState;
377
384
  readonly templates: Map<string, HTMLTemplateElement>;
@@ -383,7 +390,6 @@ declare class Ssr extends HTMLElementBase implements ISsrElement {
383
390
  private _stateData;
384
391
  private _templates;
385
392
  private _hydrateProps;
386
- get name(): string;
387
393
  get version(): string;
388
394
  get stateData(): IState;
389
395
  get templates(): Map<string, HTMLTemplateElement>;
@@ -400,7 +406,7 @@ declare class Ssr extends HTMLElementBase implements ISsrElement {
400
406
  private _loadStateData;
401
407
  private _loadTemplates;
402
408
  private _loadHydrateProps;
403
- static findByName(root: Node, name: string): ISsrElement | null;
409
+ static find(root: Node): ISsrElement | null;
404
410
  /**
405
411
  * stateData と構造テンプレート・プロパティから <wcs-ssr> の中身を構築する。
406
412
  * server パッケージの renderToString から呼ばれる。
@@ -758,12 +764,11 @@ interface IWcsManifest {
758
764
  pathDelimiter: string;
759
765
  /** ワイルドカード(`*`) */
760
766
  wildcard: string;
761
- /** バインディング構文 `[prop][#mod]: [path][@state][|filter...]` の区切り文字 */
767
+ /** バインディング構文 `[prop][#mod]: [path][|filter...]` の区切り文字 */
762
768
  delimiters: {
763
769
  binding: string;
764
770
  propValue: string;
765
771
  modifier: string;
766
- stateName: string;
767
772
  filter: string;
768
773
  };
769
774
  /** 構造ディレクティブ(`<template data-wcs="for: ...">` 等) */
@@ -828,12 +833,10 @@ declare function getWcsManifest(): IWcsManifest;
828
833
 
829
834
  type DevtoolsEvent = {
830
835
  readonly type: "state:element-registered";
831
- readonly name: string;
832
836
  readonly rootNode: Node;
833
837
  readonly element: IStateElement;
834
838
  } | {
835
839
  readonly type: "state:element-unregistered";
836
- readonly name: string;
837
840
  readonly rootNode: Node;
838
841
  readonly element: IStateElement;
839
842
  } | {
@@ -860,15 +863,20 @@ type DevtoolsEvent = {
860
863
  } | {
861
864
  readonly type: "state:token-emit";
862
865
  readonly kind: "command" | "event";
863
- readonly stateName: string | null;
864
866
  readonly tokenName: string;
865
867
  readonly args: readonly unknown[];
866
868
  readonly subscriberCount: number;
869
+ /**
870
+ * 発火元ツリーの state 要素(protocol v2 追補 2026-09-05・additive)。
871
+ * registry(getOrCreate*Token)経由で作られた token だけが持つ — 直接生成された
872
+ * token や旧ランタイムの payload には無い(optional)。無い emit の実測は
873
+ * ツリー別に分けられないため、消費側は全ツリーの照会へ合算で残す。
874
+ */
875
+ readonly stateElement?: IStateElement;
867
876
  } | {
868
877
  readonly type: "state:watch-error";
869
878
  /** throw 元。cur の評価(getter)とハンドラ本体では原因も直し方も違う */
870
879
  readonly phase: "prime" | "evaluate" | "handler";
871
- readonly stateName: string;
872
880
  /** `$watch` の宣言キー(ワイルドカードを含む生のパス) */
873
881
  readonly path: string;
874
882
  readonly error: unknown;
@@ -879,21 +887,25 @@ type DevtoolsEvent = {
879
887
  readonly paths: readonly string[];
880
888
  } | {
881
889
  readonly type: "state:watch-fired";
882
- readonly stateName: string;
883
890
  /** `$watch` の宣言キー(ワイルドカードを含む生のパス) */
884
891
  readonly path: string;
892
+ /**
893
+ * 発火元ツリーの state 要素(protocol v2 追補 2026-09-05・additive)。
894
+ * 複数ツリーが同名の watch パスを宣言するページで実測台帳をツリー別に
895
+ * 分けるための識別。旧ランタイムの payload には無い(optional)— 無い発火は
896
+ * 消費側が全ツリーの照会へ合算で残す。値を載せない契約(§4.3.1)は不変。
897
+ */
898
+ readonly stateElement?: IStateElement;
885
899
  } | {
886
900
  readonly type: "state:path-unresolved";
887
901
  /** 書き手が書いた面。診断 code が binding / watch で変わる */
888
902
  readonly source: "binding" | "watch";
889
- readonly stateName: string;
890
903
  /** 宣言されたパス(ワイルドカードを含む生の文字列) */
891
904
  readonly path: string;
892
905
  /** 解決に失敗したセグメント */
893
906
  readonly missingSegment: string;
894
907
  } | {
895
908
  readonly type: "state:binding-apply-error";
896
- readonly stateName: string;
897
909
  /** バインディングの state パス(ワイルドカードを含む生の文字列) */
898
910
  readonly path: string;
899
911
  readonly bindingType: string;
@@ -989,11 +1001,19 @@ declare function analyzeContract(manifest: IContractManifest): readonly Contract
989
1001
  declare class State extends HTMLElementBase implements IStateElement {
990
1002
  static hasConnectedCallbackPromise: boolean;
991
1003
  static getBindingsReady(rootNode: Node): Promise<void>;
1004
+ /**
1005
+ * `mount` の動的変更は未サポート(再マウントは非目標 — 設計書 §4-7)。
1006
+ * 初期化済み要素での変更は無言で捨てず warn で知らせる。初期化前の属性設定
1007
+ * (パース時・接続前の setAttribute)は正規の使い方なので黙る。
1008
+ * `name` は connectedCallback 冒頭で fail-fast 済みなので観測しない。
1009
+ */
1010
+ static get observedAttributes(): string[];
992
1011
  private __state;
993
1012
  private _hasUpdatedCallback;
1013
+ /** enable-ssr のスナップショットから初期化された(D14: ボリュームはデータを採用する) */
1014
+ private _hydratedFromSsr;
994
1015
  private _crossRowListPaths;
995
1016
  private _indexDependentGetterPaths;
996
- private _name;
997
1017
  private _initialized;
998
1018
  private _initializePromise;
999
1019
  private _resolveInitialize;
@@ -1018,7 +1038,14 @@ declare class State extends HTMLElementBase implements IStateElement {
1018
1038
  private _rootNode;
1019
1039
  private _boundComponent;
1020
1040
  private _boundComponentStateProp;
1021
- private _hasMappedComponentState;
1041
+ private _hasMounts;
1042
+ private _hasGraftedVolumes;
1043
+ /** ボリューム(mount=): 接ぎ木済みの控え($disconnectedCallback 用) */
1044
+ private _volumeGraftInfo;
1045
+ /** ボリューム: スロット予約済み・接ぎ木進行中(ロード完了前の再接続の再入ガード) */
1046
+ private _volumeInitializing;
1047
+ /** v2 マウント(Phase 2): この bind-component 要素が構築したマウント記録 */
1048
+ private _mountRecord;
1022
1049
  private _bindableEventMap;
1023
1050
  private _commandTokenNames;
1024
1051
  private _eventTokenNames;
@@ -1028,44 +1055,26 @@ declare class State extends HTMLElementBase implements IStateElement {
1028
1055
  constructor();
1029
1056
  private get _state();
1030
1057
  private set _state(value);
1031
- get name(): string;
1058
+ attributeChangedCallback(_name: string, oldValue: string | null, newValue: string | null): void;
1032
1059
  private _loadFromSsrElement;
1033
- private _initialize;
1034
- private _initializeBindWebComponent;
1060
+ /** state / src / json / inner <script> / API set のソース解決(_initialize とボリュームで共用)。 */
1061
+ private _loadStateFromSource;
1035
1062
  /**
1036
- * Light DOM の mapped コンポーネントが、自分のサブツリーのバインディングを張る(§1.13)。
1037
- *
1038
- * Shadow DOM 形では子スコープが別 rootNode にあり、`setStateElementByName` の初回登録から
1039
- * その root ぶんの `buildBindings` が別パスとして起動する。Light DOM ではホストと同じ root に
1040
- * いるためそのパスが存在せず、かといってホストのパスに混ぜると `@name` の解決が
1041
- * この要素の名前登録より先に来てしまう。そこで `getSubscriberNodes` がホスト側の走査から
1042
- * このサブツリーを外し、名前登録が済んだここで同じことを自前で行う。
1043
- *
1044
- * `{{ }}` の変換だけはホストのパスが root 全体に対して済ませている(純粋にテキスト操作で
1045
- * state に依存しないため)。構造フラグメントの収集は fragment info を rootNode + state 名で
1046
- * 登録するので state 依存であり、ホストのパスからは外してここで走らせる。
1047
- *
1048
- * ループ文脈を null で渡すのは Shadow DOM 形(`initializeBindings(shadowRoot, null)`)と
1049
- * 揃えるため —— 子孫の `getLoopContextByNode` はコンポーネント要素まで遡って
1050
- * 親スコープの行を見つける。
1063
+ * ボリューム(`<wcs-state mount="path">`): 独立ツリーを持たず、ロード完了で
1064
+ * ルートに接ぎ木する(webComponent/volume.ts)。接続時にスロットを予約(D22)。
1065
+ * ルートより先に接続されてもよい ルート登録が保留分を引き取る(V5)。
1051
1066
  */
1052
- private _initializeLightDomComponentScope;
1067
+ private _initializeVolume;
1068
+ private _initialize;
1053
1069
  /**
1054
- * mapped な `bind-component` が切断 再接続したときに、束ねているパスを読み直させる(§1.9)。
1055
- *
1056
- * リスト行の content は再利用されるので、行が作り直されると子はこの経路を通る
1057
- * (`_initialized` が真なので `_initializeBindWebComponent` / `_initialize` は走らず、
1058
- * 子のバインディングは張り直されない)。切断中に親で起きた変更の通知は
1059
- * `applyChangeToWebComponent` が切断済みを理由に落としているため、ここで読み直さないと
1060
- * 子のビューだけが古い値のまま取り残される。何が変わったかは分からないので、
1061
- * プライマリ規則の粒度で丸ごと読み直す。
1062
- *
1063
- * 読み直しの前に派生規則の memo を捨てる。派生規則の購読者(親スコープに立つ
1064
- * バインディング)は切断で teardown されており、memo が残っていると導出が二度と
1065
- * 走らないため購読者も張り直されない = 以後この子だけがサブパスの書き込みを
1066
- * 受け取れなくなる。捨てておけば、直後の読み直しで導出と購読者登録が走る。
1070
+ * 設定エラーでの fail-fast。initializePromise 等を解決してから raise する —
1071
+ * 未解決のまま投げると waitForStateInitialize(ホストの buildBindings)が
1072
+ * この要素を待ち続け、**ページ全体が無言でウェッジする**(1 つの設定ミスが
1073
+ * 無関係なバインディングまで道連れにする)。エラー自体は unhandled rejection
1074
+ * として loud に残る。
1067
1075
  */
1068
- private _reloadMappedPathsAfterReconnect;
1076
+ private _failInitialization;
1077
+ private _initializeBindWebComponent;
1069
1078
  private _callStateConnectedCallback;
1070
1079
  private _initializeDCC;
1071
1080
  private _callStateDisconnectedCallback;
@@ -1078,6 +1087,21 @@ declare class State extends HTMLElementBase implements IStateElement {
1078
1087
  get listKeys(): ListKeyMap | null;
1079
1088
  get watchPaths(): ReadonlySet<string> | null;
1080
1089
  get elementPaths(): Set<string>;
1090
+ /**
1091
+ * ボリューム(webComponent/volume.ts)のアクセサ登録: ツリーパスをキーにした
1092
+ * quoted-path アクセサを state オブジェクトに定義し、getter / setter 台帳と
1093
+ * 依存グラフに載せる。ルートのワイルドカード getter(`"children.*.label"`)と
1094
+ * 同じ機構に乗るので、評価は pushAddress 下・依存はグラフに載る。
1095
+ */
1096
+ /** ボリュームの watch パスをホットパス用ゲート(watchPaths)へ合流させる。 */
1097
+ addVolumeWatchPaths(paths: ReadonlySet<string>): void;
1098
+ /** ボリュームの $listKeys(接頭辞翻訳済み)をルートの表へ合流させる。衝突は設定ミス。 */
1099
+ mergeVolumeListKeys(entries: ReadonlyMap<string, ListKeySpec>): void;
1100
+ /** ボリュームが $updatedCallback を持つとき、収集ゲートを開ける(apply/applyChange.ts)。 */
1101
+ enableUpdatedCallback(): void;
1102
+ /** enable-ssr スナップショットから初期化されたか(D14 — webComponent/volume.ts が読む)。 */
1103
+ get hydratedFromSsr(): boolean;
1104
+ defineTreeAccessor(path: string, descriptor: PropertyDescriptor): void;
1081
1105
  get getterPaths(): Set<string>;
1082
1106
  get setterPaths(): Set<string>;
1083
1107
  get loopContextStack(): ILoopContextStack;
@@ -1085,20 +1109,13 @@ declare class State extends HTMLElementBase implements IStateElement {
1085
1109
  get staticDependency(): Map<string, string[]>;
1086
1110
  get version(): number;
1087
1111
  get rootNode(): Node;
1088
- /**
1089
- * `rootNode` を保持しているか = `createState` を呼んでよいか(§1.9)。
1090
- * disconnect で落ち、connect の冒頭で復活する。
1091
- */
1092
- get hasRootNode(): boolean;
1093
1112
  get boundComponentStateProp(): string | null;
1094
- get boundComponent(): Element | null;
1095
- get hasMappedComponentState(): boolean;
1096
- get boundPaths(): ReadonlySet<string>;
1097
- /**
1098
- * この state の実体が innerState proxy であることを記録する。唯一の呼び手は
1099
- * `bindWebComponent` の mapped 分岐(§1.8)。
1100
- */
1101
- markComponentStateMapped(): void;
1113
+ get hasMounts(): boolean;
1114
+ /** 唯一の呼び手は webComponent/mount.ts の registerMountRecord(Phase 2)。 */
1115
+ markHasMounts(): void;
1116
+ get hasGraftedVolumes(): boolean;
1117
+ /** 唯一の呼び手は webComponent/volume.ts graftVolume(D22 後段のガードが読む)。 */
1118
+ markHasGraftedVolumes(): void;
1102
1119
  get bindableEventMap(): Record<string, string>;
1103
1120
  get commandTokenNames(): ReadonlySet<string>;
1104
1121
  get eventTokenNames(): ReadonlySet<string>;
@@ -1140,7 +1157,6 @@ declare class State extends HTMLElementBase implements IStateElement {
1140
1157
  addCrossRowListPath(path: string): void;
1141
1158
  get indexDependentGetterPaths(): ReadonlySet<string>;
1142
1159
  addIndexDependentGetterPath(path: string): void;
1143
- bindProperty(prop: string, desc: PropertyDescriptor): void;
1144
1160
  setInitialState(state: Record<string, any>): void;
1145
1161
  }
1146
1162