@wcstack/state 1.30.0 → 1.32.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
@@ -42,6 +42,35 @@ interface ILoopContextStack {
42
42
  createLoopContext(elementStateAddress: IStateAddress, callback: (loopContext: ILoopContext) => void | Promise<void>): void | Promise<void>;
43
43
  }
44
44
 
45
+ /**
46
+ * pathDiagnostics.ts — バインド / `$watch` 対象パスの存在検査(silent failure の可視化)。
47
+ *
48
+ * なぜ必要か:
49
+ * `getByAddress` は「親が null / undefined のパスの読み」を undefined で返し、
50
+ * undefined はプロパティ書き込みがスキップされる値なので、`user.nmae` のような
51
+ * 打ち間違いは**エラーも警告も出さずに DOM が更新されない**だけになる。一方で
52
+ * トップレベルの打ち間違い(`cout`)は parentAddress を辿れず raiseError で落ちる。
53
+ * 同じ「パスを打ち間違えた」という 1 つの失敗が、パスの深さで silent / loud に
54
+ * 割れており、書き手からは区別がつかない。ここはその silent 側を埋める。
55
+ *
56
+ * 精度方針(過小近似):
57
+ * 「確実に存在しない」と言い切れる場合にだけ報告する。getter の戻り値の先・
58
+ * 空配列・null 親・mapped な `bind-component` など、静的に決められない形はすべて
59
+ * `"unknown"` に倒して黙る(偽陽性ゼロ優先。docs/static-wiring-dx-design.md D7 /
60
+ * [ADR-06](../../docs/architecture-hardening/06-path-type-safety.md) の精度哲学)。
61
+ *
62
+ * 診断 code はコンソール → lint → IDE の三面で共有する(errorGuidance.ts の規約)。
63
+ */
64
+
65
+ /** `setPathInfo` の呼び出し元の種別。診断 code と適用範囲がこれで変わる */
66
+ type PathInfoSource =
67
+ /** data-wcs / mustache / コメントバインディング */
68
+ "binding"
69
+ /** `$watch` の宣言キー */
70
+ | "watch"
71
+ /** ランタイム内部のパス翻訳(mapped な bind-component の外向き伝播)。検査しない */
72
+ | "internal";
73
+
45
74
  declare const setLoopContextSymbol: unique symbol;
46
75
  declare const getByAddressSymbol: unique symbol;
47
76
  declare const hasByAddressSymbol: unique symbol;
@@ -151,8 +180,11 @@ interface IStateElement {
151
180
  * パスを依存グラフへ登録する。DOM バインディング登録(BindingSession)のほか、
152
181
  * `$watch` 宣言(processWatchDeclaration)からも呼ばれる — 静的依存グラフに
153
182
  * 載るのがバインド済みパスだけだと headless 購読が成立しないため(設計書 §8)。
183
+ *
184
+ * `source` は存在検査の診断 code と適用範囲を決める(pathDiagnostics.ts)。
185
+ * 省略時は `"binding"`(テスト用モック互換のため optional)。
154
186
  */
155
- setPathInfo(path: string, bindingType: BindingType): void;
187
+ setPathInfo(path: string, bindingType: BindingType, source?: PathInfoSource): void;
156
188
  addStaticDependency(parentPath: string, childPath: string): boolean;
157
189
  addDynamicDependency(fromPath: string, toPath: string): boolean;
158
190
  createStateAsync(mutability: Mutability, callback: (state: IStateProxy) => Promise<void>): Promise<void>;
@@ -315,7 +347,7 @@ interface IWritableConfig {
315
347
  sameValueGuard?: boolean;
316
348
  }
317
349
 
318
- declare function bootstrapState(config?: IWritableConfig): void;
350
+ declare function bootstrapState(config?: IWritableConfig, registry?: CustomElementRegistry): void;
319
351
 
320
352
  declare function getConfig(): IConfig;
321
353
 
@@ -489,7 +521,10 @@ interface WcsStateApi {
489
521
  * ワイルドカードを含むパスにマッチする全要素を配列で取得する。
490
522
  *
491
523
  * @param path - ワイルドカードを含むパス
492
- * @param indexes - 各ワイルドカード階層のインデックス(省略時はループコンテキストから解決)
524
+ * @param indexes - 各ワイルドカード階層のインデックス(前方一致の接頭辞。`[]` は全階層を展開)。
525
+ * 省略時はループ文脈の添字(`[$1..$n]` 相当)のうち path と共有するワイルドカード連鎖の
526
+ * 分が接頭辞として敷かれる(文脈が path より深い分は切り詰め)。共有が無いのに文脈が
527
+ * 添字を持つ場合は throw する — 異なる文脈の添字は流用しない。
493
528
  *
494
529
  * @example
495
530
  * ```ts
@@ -499,6 +534,34 @@ interface WcsStateApi {
499
534
  * ```
500
535
  */
501
536
  $getAll<V = any>(path: string, indexes?: number[]): V[];
537
+ /**
538
+ * ワイルドカードを含むパスにマッチする**全アドレスへ一括で書き込む**(`$getAll` の対称形)。
539
+ *
540
+ * 配列を作り直さずに一括更新するための API。`this.users = this.users.map(...)` は
541
+ * ListIndex・行 getter キャッシュ・差分描画をまとめて作り直すが、`$setAll` は
542
+ * in-place な個別書き込みに分解するのでリストの同一性が保たれる。
543
+ *
544
+ * - `indexes` は `$getAll` と同じ**前方一致の接頭辞**(`[]` で全階層を展開)。省略は不可。
545
+ * - 関数を渡すと **mapper**(`(current, ...indexes) => next`)として要素ごとに評価される。
546
+ * - 配列は既定でブロードキャストされる。1 件ずつ配るには `{ spread: true }` を明示する。
547
+ * - `undefined` を書こうとした要素はスキップされる(クリアは `null`)。
548
+ *
549
+ * @returns 実際に書き込んだ件数(`undefined` でスキップした分を含まない)
550
+ *
551
+ * @example
552
+ * ```ts
553
+ * toggleAll(e: Event) {
554
+ * this.$setAll("users.*.selected", [], (e.target as HTMLInputElement).checked);
555
+ * }
556
+ * invertAll() {
557
+ * this.$setAll("users.*.selected", [], cur => !cur);
558
+ * }
559
+ * ```
560
+ */
561
+ $setAll<V = any>(path: string, indexes: number[], value: V | ((current: V, ...indexes: number[]) => V | undefined)): number;
562
+ $setAll<V = any>(path: string, indexes: number[], values: readonly V[], options: {
563
+ spread: true;
564
+ }): number;
502
565
  /**
503
566
  * 指定パスの更新を手動でトリガーする。
504
567
  * Proxy の set トラップを経由せずに内部状態を変更した場合に使用。
@@ -812,6 +875,22 @@ type DevtoolsEvent = {
812
875
  readonly stateName: string;
813
876
  /** `$watch` の宣言キー(ワイルドカードを含む生のパス) */
814
877
  readonly path: string;
878
+ } | {
879
+ readonly type: "state:path-unresolved";
880
+ /** 書き手が書いた面。診断 code が binding / watch で変わる */
881
+ readonly source: "binding" | "watch";
882
+ readonly stateName: string;
883
+ /** 宣言されたパス(ワイルドカードを含む生の文字列) */
884
+ readonly path: string;
885
+ /** 解決に失敗したセグメント */
886
+ readonly missingSegment: string;
887
+ } | {
888
+ readonly type: "state:binding-apply-error";
889
+ readonly stateName: string;
890
+ /** バインディングの state パス(ワイルドカードを含む生の文字列) */
891
+ readonly path: string;
892
+ readonly bindingType: string;
893
+ readonly error: unknown;
815
894
  } | {
816
895
  readonly type: "propagation:suppressed";
817
896
  readonly reason: "confirmation" | "visited-edge";