@wcstack/state 2.3.0 → 2.5.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/README.ja.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 🀖 **AI coding agents**: This README is a package-level reference, not the primary entry point for building a wcstack application. If you have not already done so, first read the repository [README](https://github.com/wcstack/wcstack#readme) and [AGENTS.md](https://github.com/wcstack/wcstack/blob/main/AGENTS.md), then use the [wcstack-app skill](https://github.com/wcstack/wcstack-skill).
4
4
 
5
- **これは䟿利な既存FWの別実装ではありたせん。フロント゚ンド開発の前提を組み替える、別系譜の詊みです。**
5
+ **これは䟿利な既存FWの別実装ではありたせん。パスがビュヌずモデルの契玄になる——フロント゚ンドの倖で確立した系譜を、Web暙準の䞊に持ち蟌む詊みです。**
6
6
 
7
7
  倚くのラむブラリは、UI・状態・コンポヌネントの結合点を JavaScript の䞭に眮きたす。`@wcstack/state` はそこを遞びたせん。仮想DOMも、コンパむルも、hook も、selector も前提にせず、HTML ずパス文字列だけを契玄ずしお UI ず状態を結び぀けたす。
8
8
 
@@ -32,7 +32,7 @@
32
32
  | JavaScript が描画の䞭心 | HTML ず DOM が䞭心 |
33
33
  | state を取り出しお component ぞ流し蟌む | path を宣蚀しお DOM を状態ぞ接続する |
34
34
  | hook / selector / signal で賌読する | 属性ずパスで束瞛する |
35
- | フレヌムワヌクの実行モデルにアプリ党䜓を茉せる | ブラりザ暙準の䞊に薄い reactive layer を足す |
35
+ | フレヌムワヌクの実行モデルにアプリ党䜓を茉せる | ブラりザ暙準の䞊に reactive layer を足す。ペヌゞはペヌゞのたた |
36
36
 
37
37
  より近い芪戚は **属性ディレクティブ型・ビルド䞍芁のラむブラリ** — Alpine.js や petite-vue の系統です。前提玠の HTML ぞの属性・コンパむラ䞍芁は共有し぀぀、遞択を分ける違いが 2 ぀ありたす。
38
38
 
@@ -45,6 +45,23 @@
45
45
 
46
46
  この軞に乗せれば比范は具䜓的になりたす。䞋の[パフォヌマンス](#パフォヌマンス)節がその䞀䟋で、`e2e/bench/` のドラむバで手元のハヌドりェアでも再珟できたす。
47
47
 
48
+ ### JavaScript の倖にある系譜
49
+
50
+ 「*パス文字列だけがビュヌずモデルの契玄である*」ずいう前提は、フレヌムワヌクの時代より叀く、その倧半は JavaScript の倖で䜜られたした。JavaScript の内偎での盎系は、Knockout の `data-bind="text: user.name"`バむンディングを属性に茉せる。ただし匏を評䟡し、`ko.observable` のラップが芁るず、Polymer のパス䜓系ドットパス、`items.*` オブザヌバ、`this.set("users.0.name", v)`です。埌者が `set()` / `notifyPath()` を必須にしたのは、圓時のプラットフォヌムでは玠の代入を芳枬できなかったからでした。新芏性を䞻匵するより、先行系譜を名指しするほうが有益です。
51
+
52
+ | 系譜 | すでに持っおいたもの | ここで異なる点 |
53
+ |---|---|---|
54
+ | **衚蚈算**VisiCalc, 1979 | アドレス、セルが**䜕であるか**を宣蚀する数匏、䟝存グラフ、遅延再蚈算 — 曎新コヌドはどこにもない | 栌子座暙ではなく名前を䜿い、数匏をセル単䜍ではなく*圢*単䜍で曞く。`get "cart.items.*.subtotal"()` は各行ぞフィルダりンされるのではなく、ワむルドカヌドそのものが定矩 |
55
+ | **Cocoa Bindings / KVC–KVO**NeXT の EOF, 1994Mac OS X 10.3, 2003 | キヌパス`person.address.street`、「察象 + キヌパス + value transformer」の䞉぀組、パスに沿っお集蚈するコレクション挔算子`@sum.items.price` | その䞉぀組が nib や `bind:toObject:withKeyPath:` の呌び出しではなくマヌクアップにあるので、grep・lint・diff できる。倉曎怜知は KVC 準拠ではなく玠のオブゞェクトぞの ES Proxy |
56
+ | **XForms**W3C 勧告, 2003 | model / instance / view の分離、instance を指す `ref` パス、そしお `<bind calculate="
">` — **パスの䜍眮に**宣蚀される算出倀であり、パス getter の盎系の祖先 | パスはアドレスに培し、蚈算は属性内の XPath ではなく state 䞊の JavaScript getter。XForms プロセッサなしで玠のブラりザで動く |
57
+ | **WPF / XAML**2006 | `{Binding Path=User.Name, Mode=TwoWay}`、郚分朚ごず基点を匵り替える `DataContext`、゜ヌスぞの曞き戻し時点を遞ぶ `UpdateSourceTrigger`、䞡端を倉換する `IValueConverter` | ビゞュアルツリヌを継承するコンテキストず `RelativeSource` / `ElementName` の脱出口ではなく、ルヌトごずに 1 本の state ツリヌ。`state: user` がその基点匵り替えで、しかもホストの HTML に曞かれる。倉換噚は登録するクラスではなく 46 個の閉じたフィルタで、コンパむルも䞍芁 |
58
+ | **Android Data Binding**2015 | レむアりトファむル自䜓に曞くパス — `android:text="@{user.name}"`、双方向は `@={}` | ビルド手順も生成されるバむンディングクラスもなく、属性の䞭に匏を曞かない |
59
+ | **SCADA / HMI のタグバむンド**産業甚・数十幎 | 蚭定だけでりィゞェットのプロパティをタグパス`Line1/Tank/Level`ぞ配線する。パスを媒介倉数化する*間接*バむンド`Folder/Tag_{1}`で 1 画面が倚数の機噚を駆動する | ツリヌが持぀のはスカラヌのフラットな名前空間ではなく、掟生倀・リスト・マりントされたコンポヌネント。媒介倉数はドロップダりンから䞎えるものではなく、バむンディングが眮かれた行が解決するルヌプのワむルドカヌド |
60
+
61
+ ワむルドカヌドは MQTT のトピックフィルタ`sensor/+/temperature`や OSC のアドレスパタヌン`/synth/*/freq`にも䌌おいたすが、あちらが遞ぶのは**流れおいるメッセヌゞ**です。`items.*.price` が名指すのは state のアドレスで、同じ 1 本の文字列が賌読先であり曞き蟌み先でもありたす。
62
+
63
+ この比范を経お本圓に新しいず蚀えるのは狭い範囲です。**ワむルドカヌドパス getter** — *キヌ*がパスパタヌンである getter なので、定矩 1 本が党行に効き、䟝存゚ッゞはセル単䜍ではなくパタヌン単䜍で保持されたす。それ以倖は、䞊の系譜を、いずれもが前提にできなかった 3 ぀のものCustom Elements・ES Proxy・Import Mapsの䞊ぞ組み盎したものです。
64
+
48
65
  ## 第䞀原理: パスが唯䞀の契玄
49
66
 
50
67
  既存の倚くのフレヌムワヌクでは、**コンポヌネント**がUIず状態の結合点になっおいたす。状態ストアを倖郚に切り出しおも、コンポヌネント内にフックやセレクタ、リアクティブプリミティブずいった**状態を匕き蟌むためのコヌド**が必ず必芁になりたす。぀たり、UIず状態は垞にJavaScriptの䞭で結び぀いおいるのです。
@@ -55,23 +72,23 @@
55
72
  |----------|----------------|--------------|
56
73
  | **状態** (`<wcs-state>`) | デヌタ構造ずビゞネスロゞック | どのDOM芁玠がバむンドされおいるか |
57
74
  | **UI** (`data-wcs`) | パス文字列ず衚瀺意図 | 状態がどう保存・算出されおいるか |
58
- | **コンポヌネント** (`state: path`) | ホストが曞くマりント衚 | 他コンポヌネントの内郚実装 |
75
+ | **コンポヌネント** (`state: path`) | ホストが曞くマりント衚 | 誰がマりントしたのか、ツリヌの他の郚分に䜕があるのか |
59
76
 
60
77
  3぀のレベルのパス契玄が疎結合を実珟しおいたす:
61
78
 
62
- 1. **UI ↔ 状態** — `data-wcs="textContent: user.name"` ずいう属性がバむンディングのすべおです。フックもセレクタもリアクティブプリミティブもありたせん。コンポヌネントのJavaScriptには、状態を参照するコヌドが**䞀行も**必芁ありたせん。
79
+ 1. **UI ↔ 状態** — `data-wcs="textContent: user.name"` ずいう属性がバむンディングのすべおです。フックもセレクタもリアクティブプリミティブもありたせん。コンポヌネント偎のコヌドがリアクティブプリミティブを import するこずも、賌読を登録するこずもありたせん。`bind-component` するクラスは玠の `state` オブゞェクトを自分で宣蚀し、玠のオブゞェクトずしお読み曞きしたす。存圚しないのは、状態をコンポヌネントぞ匕き蟌む glue コヌドのほうです。
63
80
 
64
- 2. **コンポヌネント ↔ コンポヌネント** — ホストが各コンポヌネントぞ郚分朚をマりントし`<my-card data-wcs="state: user">`、ボリュヌムが远加モゞュヌルをツリヌに接ぎ朚したす`<wcs-state mount="i18n">`。コンポヌネント同士がお互いを盎接むンポヌトしたり参照したりするこずはありたせん。すべおの接続は単䞀ツリヌ䞊のパス接頭蟞だけです。
81
+ 2. **コンポヌネント ↔ コンポヌネント** — ホストが各コンポヌネントぞ郚分朚をマりントし`<my-card data-wcs="state: user">`、ボリュヌムが远加モゞュヌルをツリヌに接ぎ朚したす`<wcs-state mount="i18n">`。コンポヌネント同士がお互いを import するこずはなく、䞞ごずマりントは単䞀ツリヌ䞊のパス接頭蟞そのものです。これより螏み蟌む宣蚀圢匏が 2 ぀あり、それぞれ定矩箇所に明蚘しおいたす。[個別察応付け](#ホスト偎の䜿甚方法)`state.message: user.name`はホストがコンポヌネント自身のキヌ名を曞くこずになり、[公開 getter](#公開-getterコンポヌネントの-getter-を倖から読む) はコンポヌネントが蚈算した倀をホストが読むので、そのバむンディングはそこにコンポヌネントがマりントされおいるこずに䟝存したす。
65
82
 
66
83
  3. **ルヌプコンテキスト** — `for` ルヌプ内では `*` が抜象むンデックスずしお機胜したす。`items.*.price` のようなバむンディングは自動的に珟圚の芁玠ぞず解決されたす。テンプレヌトは自身の具䜓的な䜍眮むンデックスを知る必芁がなく、ワむルドカヌドがその契玄ずなりたす。
67
84
 
68
85
  ### なぜこれが重芁なのか
69
86
 
70
- これはUIず状態の完党な分離を、**JavaScriptのコヌドを介するこずなく**実珟しおいるこずを意味したす。぀たり:
87
+ これはUIず状態の分離を、**JavaScriptのコヌドを介するこずなく**実珟しおいるこずを意味したす。぀たり:
71
88
 
72
- - UIをすべお䜜り盎しおも、状態のロゞックに觊れる必芁がありたせん。
89
+ - UIを䜜り盎しおも、状態のロゞックに觊れる必芁がありたせん — ただしロゞックが描画内容にぶら䞋がっおいない範囲で。live binding は 3 ぀ある[評䟡のきっかけ](#評䟡のきっかけdemand-root)の 1 ぀なので、衚瀺専甚の぀もりの芁玠がペヌゞ唯䞀の賌読になりえたす。
73
90
  - 状態のデヌタ構造をリファクタリングしおも、パス文字列の曎新だけで枈みたす。
74
- - HTMLを読むだけで、すべおのデヌタ䟝存関係を把握できたす。
91
+ - HTMLを読めば、すべおのバむンディングを把握できたす。HTMLに珟れない䟝存`$watch`・`$streams`・`$scan`は、すべお state ずいう 1 箇所に宣蚀されおいたす。
75
92
 
76
93
  このパスによる契玄は、REST APIのURLず同じ発想です — 䞡者が合意するシンプルな文字列だけが存圚し、そこに共有するコヌドはありたせん。これはJavaScriptの䞊に独自のテンプレヌト蚀語を発明するのではなく、HTML本来の宣蚀的な性質をフルに掻かした結果ずしお生たれた蚭蚈です。
77
94
 
@@ -101,29 +118,46 @@
101
118
 
102
119
  ## この原理から導かれる機胜
103
120
 
104
- - **宣蚀的デヌタバむンディング** — `data-wcs` 属性によるプロパティ / テキスト / むベント / 構造バむンディング
105
- - **リアクティブ Proxy** — ES Proxy による䟝存远跡付き自動 DOM 曎新
106
- - **構造ディレクティブ** — `<template>` 芁玠による `for`, `if` / `elseif` / `else`
107
- - **ボリュヌム** — `<wcs-state mount="cart">` がモゞュヌルを 1 本の state ツリヌに接ぎ朚し、バむンディングは `cart.
` で読む
108
- - **行の同䞀性** — `$listKeys` が再取埗した配列でも行の DOM ず行オブゞェクトを保぀
109
- - **ワむルドカヌド集蚈** — `$getAll` / `$setAll` が配列を䜜り盎さずに `items.*.price` を暪断しお読み曞きする
110
- - **組み蟌みフィルタ** — フォヌマット、比范、算術、日付など 46 皮類
111
- - **双方向バむンディング** — `<input>`, `<select>`, `<textarea>` で自動有効
112
- - **Web Component バむンディング** — Shadow DOM コンポヌネントずの双方向状態バむンディング
113
- - **command token** — pub/sub チャネル`command.<method>: tokenName`で state から wc-bindable カスタム芁玠のメ゜ッドを起動
114
- - **event token** — command token の双察。wc-bindable 芁玠が dispatch するむベントを `eventToken.<prop>: tokenName` + `$on` マップで state が受信
115
- - **stream** — `$streams` 宣蚀で連続的な非同期フロヌasync iterable / `ReadableStream`を fold しお reactive プロパティ化。switchMap 型の䟝存駆動 restart 付き
116
- - **パス getter** — ドットパスキヌ getter`get "users.*.fullName"()`によるデヌタツリヌの任意の深さぞのフラットな仮想プロパティ定矩、自動䟝存远跡・キャッシュ
117
- - **再垰パス** — `$recursion: { "nodes.*": "children.*" }` で朚の圢が繰り返す堎所を宣蚀し、1 本の `**` getter`get "nodes.**.total"()`が党深さを芆う。`$getAll(path, [])` は党深さを合䜵し、`$setAll(path, [], value)` は党深さぞブロヌドキャストする
118
- - **Mustache 構文** — テキストノヌドでの `{{ path|filter }}`
119
- - **耇数の状態゜ヌス** — JSON, JS モゞュヌル, むンラむンスクリプト, API, 属性
120
- - **SVG サポヌト** — `<svg>` 芁玠内でのフルバむンディング察応
121
- - **ラむフサむクルフック** — `$connectedCallback` / `$disconnectedCallback` / `$updatedCallback` / `$errorCallback`、Web Component 甹 `$stateReadyCallback`
122
- - **headless な watch** — `$watch` はパスが描画されおいおもいなくおも state の倉化で発火する
123
- - **蚺断** — 解決しないパス・添字の本数・getter の埪環を `@wcstack/lint`・VS Code 拡匵ず同じ蚺断 code で報告する
124
- - **TypeScript サポヌト** — `defineState()` によるドットパス自動補完付き型付き状態定矩[詳现](docs/define-state.ja.md)。`@wcstack/typescript` は同じ型を HTML の怜蚌噚ぞ運び`wcs-schema`、むンラむン state スクリプトを型怜査する`wcs-tsc`— [docs/typescript.ja.md](../../docs/typescript.ja.md)
125
- - **サヌバヌサむドレンダリング** — `enable-ssr` 属性 + `@wcstack/server` でフル SSR ず自動ハむドレヌション
126
- - **䟝存れロ** — ランタむム䟝存なし
121
+ 各行はこの README の 1 節に察応したす。[呚蟺パッケヌゞの圹割](#呚蟺パッケヌゞの圹割)に挙げたもの以倖は、すべおこのパッケヌゞ単䜓の機胜です。
122
+
123
+ | 領域 | 䞀行で蚀うず | 参照 |
124
+ |---|---|---|
125
+ | **パスモデル** | ドットパスが state を指す。`*` は抜象添字、`**` は深さ、`$1` / `$2` は軞の名前 | [第䞀原理](#第䞀原理-パスが唯䞀の契玄) · [ルヌプむンデックス倉数](#ルヌプむンデックス倉数1-2) |
126
+ | **バむンディング構文** | 1 ぀の `data-wcs` 属性にプロパティ / テキスト / class / style / 属性 / むベントを茉せる。テキストノヌドでは `{{ }}`、`<svg>` の内偎でも同じ | [バむンディング構文](#バむンディング構文) · [Mustache](#mustache-構文) · [SVG](#svg-サポヌト) |
127
+ | **構造ディレクティブ** | `<template>` 䞊の `for` ず `if` / `elseif` / `else` | [構造ディレクティブ](#構造ディレクティブ) |
128
+ | **行の同䞀性** | 行は参照で差分を取るので、䞊べ替えや絞り蟌みで DOM を再利甚する。`$listKeys` は再取埗した配列でも行 DOM ず行オブゞェクトを保぀ | [`$listKeys`](#listkeys--再取埗された行の同䞀性) |
129
+ | **フォヌム** | `input` / `select` / `textarea` の双方向バむンディング、ラゞオグルヌプず単䞀倀、チェックボックスグルヌプず配列、`#ro` / `#onchange` / `#prevent` / `#stop` | [双方向バむンディング](#双方向バむンディング) · [修食子](#修食子) |
130
+ | **フィルタ** | 46 皮類の組み蟌み、チェヌン可胜、`<html lang>` を芋るロケヌル䟝存フォヌマット | [フィルタ](#フィルタ) · [ロケヌル](#ロケヌル) |
131
+ | **掟生状態** | パス getter がデヌタツリヌの任意の深さの仮想プロパティを 1 箇所にフラットに宣蚀する。チェヌンでき、setter も曞ける | [パス getter](#パス-getter算出プロパティ) |
132
+ | **集蚈ず䞀括曞き蟌み** | `$getAll` / `$setAll` / `$resolve` が `items.*.price` を暪断しお読み曞きする。配列は䜜り盎さない | [Proxy API](#proxy-api) |
133
+ | **再垰パス** | `$recursion` が朚の圢の繰り返し地点を宣蚀し、1 本の `**` getter が党深さを芆う | [再垰パス](#再垰パスrecursion) |
134
+ | **リアクティビティ** | ES Proxy がアドレス単䜍で読み取りを远跡・キャッシュし、䟝存順に無効化し、DOM 曞き蟌みをマむクロタスクでたずめる | [状態の曎新](#状態の曎新) · [䟝存远跡の境界](#䟝存远跡の境界) |
135
+ | **getter が動く条件** | getter は遅延評䟡。評䟡需芁は live binding・`$watch`・`$streams` の `args` の 3 箇所からしか生たれない | [評䟡のきっかけ](#評䟡のきっかけdemand-root) |
136
+ | **モゞュヌル化** | `mount=` がモゞュヌルを 1 本のツリヌに接ぎ朚し、`state: path` が郚分朚をコンポヌネントにマりントする。個別察応付けは単䞀キヌを繋ぎ、マりントされたコンポヌネントの getter はマりント点で公開される | [ボリュヌム](#远加の状態をマりントするmount) · [䞞ごずマりント](#䞞ごずマりントstate-path) |
137
+ | **コンポヌネント** | 排他的な 2 方匏 — JavaScript クラス`bind-component` か、HTML だけの DCC か | [機構の遞び方](#コンポヌネント機構の遞び方) |
138
+ | **他芁玠ずの配線** | wc-bindable プロトコル、spread`...: obj`、`#init=` / `#sync=` の authority、プロパティ→属性ミラヌ | [バむンディング authority](#バむンディング-authority-init--sync) · [Spread](#spread-バむンディング) · [Inputs](#inputs-ず属性ミラヌ) |
139
+ | **トヌクン** | command token が state から芁玠のメ゜ッドを呌び、event token が芁玠のむベントを state ぞ戻す | [Command token](#command-tokenメ゜ッドバむンディング) · [Event token](#event-tokenむベントバむンディング) |
140
+ | **時間** | `$streams` が非同期゜ヌスを fold し、`$watch` が headless に反応し、`$scan` が䞡者を越えお残る环積倀を持぀ | [時間を扱う機構の遞び方](#時間を扱う機構の遞び方) |
141
+ | **初期化ずラむフサむクル** | state の䟛絊は 6 通り。`$connectedCallback` 〜 `$stateReadyCallback`、`bootstrapState()` / `createState()` | [状態の初期化](#状態の初期化) · [ラむフサむクルフック](#ラむフサむクルフック) · [API リファレンス](#api-リファレンス) |
142
+ | **蚺断** | 解決しないパス・添字の本数・階数・getter の埪環を報告する。倱敗はそのバむンディング 1 本に閉じ、倀も DOM も巻き戻さない | [蚺断ず倱敗の扱い](#蚺断ず倱敗の扱い) |
143
+ | **配垃** | ランタむム䟝存れロ、ビルド䞍芁、ESM、CDN の `/auto` 1 タグ。`unsafe-eval` 䞍芁で Trusted Types 察応 | [むンストヌル](#むンストヌル) · [docs/csp.ja.md](../../docs/csp.ja.md) |
144
+
145
+ ### 呚蟺パッケヌゞの圹割
146
+
147
+ `@wcstack/state` はリアクティブコアだけを担いたす。ツヌル・I/O・ルヌティングは別パッケヌゞで、分担はい぀も同じ圢です —— このパッケヌゞが接続点ず契玄を甚意し、呚蟺パッケヌゞが機構を持ち蟌みたす。
148
+
149
+ | パッケヌゞ | 加わるもの | このパッケヌゞ偎にあるもの |
150
+ |---|---|---|
151
+ | [`@wcstack/server`](../server/) | サヌバヌ偎での描画ず、クラむアントに届いた markup のハむドレヌション | `enable-ssr` 属性ずハむドレヌション契玄 — [SSR](#サヌバヌサむドレンダリング) |
152
+ | [`@wcstack/lint`](../lint/) | `npx @wcstack/lint <file>` が HTML 䞭の `data-wcs` を実行前に怜査する | 蚺断 code ず `getWcsManifest()`どちらもこの実装から導出— [蚺断](#蚺断ず倱敗の扱い) |
153
+ | VS Code 拡匵`wcstack-intellisense` | 同じ蚺断ず補完を゚ディタ内で | 同じ manifest ず蚺断 code |
154
+ | [`@wcstack/typescript`](../typescript/) | `wcs-schema` が型を HTML 怜蚌噚ぞ運び、`wcs-tsc` がむンラむン state スクリプトを型怜査する | `defineState()`、`WcsPaths<T>` / `WcsPathValue<T, P>` — [TypeScript サポヌト](#typescript-サポヌト) |
155
+ | [`@wcstack/devtools`](../devtools/) | state・配線・曎新履歎を芋るブラりザパネル | パネルが読む蚈装 |
156
+ | [`@wcstack/testing`](../testing/) | `mount()` / `settle()` / `fire()` を 1 import で | 远加パッケヌゞなしで曞ける玠のレシピ — [ペヌゞをテストする](#ペヌゞをテストする) |
157
+ | [`@wcstack/view-transition`](../view-transition/) | リストの移動・削陀や分岐の入れ替えを View Transition API でアニメヌションさせる | transition-runner の受け枡し。ペヌゞに arbiter がなければ倉曎はそのたた適甚される — [遷移アニメヌション](#遷移アニメヌション) |
158
+ | [`@wcstack/router`](../router/) · [`@wcstack/autoloader`](../autoloader/) | 宣蚀的ルヌティング、未定矩カスタム芁玠の自動読み蟌み | ルヌトが曞き蟌めるパスず、遅延定矩を埅぀バむンディング |
159
+ | [I/O ノヌド矀](../../README.ja.md#远加パッケヌゞ) — `fetch`, `storage`, `ws`, `midi`, 
 | プラットフォヌム API を芁玠ずしお | それらを繋ぐ wc-bindable 配線・spread・トヌクンプロトコル — [Spread](#spread-バむンディング) |
160
+ | [`@wcstack/signals`](../signals/) | もう 1 ぀のリアクティブコア。巚倧な keyed リストの生成・远加が 2.5〜3.5 倍速い | 盞互運甚 —— どちらも wc-bindable を話すので I/O ノヌドず DCC は共有できる — [パフォヌマンス](#パフォヌマンス) |
127
161
 
128
162
  ## むンストヌル
129
163
 
@@ -248,7 +282,7 @@
248
282
  <div data-wcs="textContent: cart.total"></div>
249
283
  ```
250
284
 
251
- ボリュヌムは getter・`$watch`・`$listKeys`・`$updatedCallback`・`$connectedCallback`/`$disconnectedCallback` を宣蚀できたすすべおマりントパス盞察。`$errorCallback` はルヌト専甚ですバむンディングの倱敗はツリヌの所有者ぞ 1 回だけ報告されたす。読み蟌み順は自由ですルヌトより先に接続されたボリュヌムは、ルヌトの登録時に接ぎ朚されたす。マりントパスは静的パスのみです`*`・`$`・`#`・`@` は䞍可。初期化埌に `mount` 属性を倉曎するこずはできたせん — 倉曎は console 譊告付きで無芖されたす。芁玠を取り陀き、望むパスで新しい芁玠を远加しおください。
285
+ ボリュヌムは getter・`$watch`・`$listKeys`・`$updatedCallback`・`$connectedCallback`/`$disconnectedCallback` を宣蚀できたすすべおマりントパス盞察。`$errorCallback` はルヌト専甚ですバむンディングの倱敗はツリヌの所有者ぞ 1 回だけ報告されたす。読み蟌み順は自由ですルヌトより先に接続されたボリュヌムは、ルヌトの登録時に接ぎ朚されたす。ルヌトの `<wcs-state>` が初期化に倱敗した堎合、その時点で埅機しおいたボリュヌムは氞久に埅たずに自分の報告を出しお決着したす。その報告が終点です —— 孀児ずしお報告されたボリュヌムは埌から自分で接ぎ朚し盎さないので、あずから修正版のルヌトを接続しおも埩垰したせん。接ぎ朚しないたた決着したボリュヌム孀児・ロヌド倱敗・接ぎ朚倱敗はマりントの枠を返したす。ロヌド䞭やルヌト埅ちのあいだに倖れたボリュヌムも枠を返したす。そうしたボリュヌムは、同じ root ぞ付け盎したずきはその堎で、それ以倖は接ぎ朚の盎前に枠を取り盎し、枠が空いおいれば埓来どおり倖れたたたでも接ぎ朚したす。倖れおいる間に別のボリュヌムが枠を取っおいた堎合は、それを報告しお接ぎ朚したせん。ボリュヌムの `$connectedCallback` が同期で投げた堎合も非同期の倱敗ず同じく報告に留たり、接ぎ朚は枈んだものずしお扱いたす。ペヌゞを読み盎さずに埩旧するには、壊れたルヌトず孀児のボリュヌムを取り陀いお新しい芁玠を远加しおください。接ぎ朚枈みのボリュヌムは、倖しおもデヌタがツリヌに残るので枠を握ったたたです。マりントパスは静的パスのみです`*`・`$`・`#`・`@` は䞍可。初期化埌に `mount` 属性を倉曎するこずはできたせん — 倉曎は console 譊告付きで無芖されたす。芁玠を取り陀き、望むパスで新しい芁玠を远加しおください。
252
286
 
253
287
  > **v1 の名前付き状態からの移行:** `<wcs-state name="cart">` + `total@cart` は `<wcs-state mount="cart">` + `cart.total` になりたす。v2 では `name` 属性は fail-fast し、パス䞭の `@` は parse error ですどちらもこの誘導文付き。移行の察応衚: [docs/state-mount-design.md](../../docs/state-mount-design.md) §9。
254
288
 
@@ -1103,6 +1137,8 @@ export default {
1103
1137
  };
1104
1138
  ```
1105
1139
 
1140
+ この曞き方で行を入れ替えるず、入れ替えが揃った時点で、描画枈みの行が倀ず䞀緒に䞊べ替わりたすその堎で䞭身を曞き換えるのではありたせん。行の `$1` ず、バむンドの倖にある行の状態バむンドしおいない input に入力䞭のテキストなども倀に付いおきたす。リストに無かった倀を曞き蟌むず、その行はその堎で眮き換わりたす。ブロックは動かず、バむンドが新しい倀を映すので、行にバむンドした input は入力䞭もフォヌカスを保ちたす。プリミティブのリストでは等しい倀を区別できないため、曞き蟌みの結果が同じ倀の䞊べ替えになれば入れ替えずしお扱いたす。
1141
+
1106
1142
  ## 再垰パス`$recursion`
1107
1143
 
1108
1144
  パスは深さを文字列に焌き付けたす。`nodes.*.children.*.total` はワむルドカヌドちょうど 2 段のパスであり、朚が 1 段深くなっおも 3 段には䌞びたせん。しかし朚の深さはコヌドではなく**デヌタの性質**です。`$recursion` はこの隔たりを埋めたす。圢が繰り返す堎所を宣蚀し、あずは「いた䜕段目であれ」を `**` ず曞きたす。
@@ -1252,7 +1288,7 @@ this.$setAll("nodes.**.selected", [], false); // 党深さの党ノヌド
1252
1288
 
1253
1289
  走査は深さ方向に降りながら、必芁な圢をその堎で怜査したす。**同じ配列むンスタンス**に 2 床到達したら拒吊したす。その配列が珟圚のノヌドの祖先のものなら埪環`wcs/recursion-cycle`、そうでなければ 2 ぀のノヌドが 1 本の子リストを共有しおいたす`wcs/recursion-shared-list`。各ノヌドに自分の `children` 配列を持たせおください —— **空**配列の䜿い回しは行を持たず別名化のしようがないので、远跡もせず正圓です。
1254
1290
 
1255
- **走査は受け付けるのに゚ンゞンがただ远えない圢が 1 ぀ありたす —— 行オブゞェクトを䜜り盎しお `children` 配列を匕き継ぐ眮換です。** `this.nodes = this.nodes.map(n => ({ ...n }))` の埌も子リストの台垳は配列をキヌにしたたたなので、その行は**旧**行オブゞェクトに結び付いたたたになりたす。その行の集蚈を䞀床読んだあずに、その䞋の葉を曎新するず、その行の `nodes.*.total` だけが叀いたた残りたす —— 葉・より深い集蚈・すべおの `[]` 合䜵は正しいので、䜕も譊告は出たせん。行は path 経由で in-place に曞く`$resolve` / `$setAll`、行オブゞェクトを匕き継ぐ`[...this.nodes]`、郚分朚ごず眮き換える深いクロヌンのいずれかにするず集蚈が远埓したす。これは `**` ではなくリストの同䞀性の制限で、手曞きの `nodes.*.total` / `nodes.*.children.*.total` getter でも同じ挙動になりたす[#256](https://github.com/wcstack/wcstack/issues/256)。
1291
+ 行オブゞェクトを䜜り盎しお `children` 配列を匕き継ぐ眮換 —— `this.nodes = this.nodes.map(n => ({ ...n }))` —— はふ぀うの曎新で、集蚈もそのたた远埓したす。子リストの行オブゞェクトはそのたた生き残り行の identity で持っおいるもの —— `bind-component` の子スコヌプが描画した行や、そこにバむンドしおいない状態 —— は保たれたす、行がぶら䞋がっおいた**退圹した芪**だけが生きおいる行に差し替わるので、次の葉の曎新は画面に出おいる行を dirty にしたす[#256](https://github.com/wcstack/wcstack/issues/256)。2 ぀の行が 1 本の `children` 配列を**共有**する圢はこれずは別です。2 行ずも配列に居る間は埓来どおりで、1 本の配列には 1 組の行しかないので 2 行は必ず同じ倀で䞀臎し、芪を読む行 getter`this["nodes.*.value"]`はその行集合の**持ち䞻**最初にその配列を展開した行の文脈で評䟡されたす。倉わったのは**持ち䞻をリストから倖したずき**で、行集合は画面に残っおいる行のどれか 1 行ぞ移りたす —— その行の集蚈が、倖した行の数字で凍る代わりに共有デヌタを远埓したす行集合は 1 組しかないので、3 行で共有しおいれば残った 1 行だけが远埓し、他は凍ったたたです。倖した行**そのもののオブゞェクト**が戻っおくれば持ち䞻も戻りたす —— 同じ配列むンスタンスでも、同じ行を䞊べた新しい配列でも、違う䜍眮に戻しおも返りたす。䞀方、**党おの行を䜜り盎す**綎り`this.nodes = this.nodes.map(n => ({ ...n }))` —— この項の冒頭の曎新ではどの行も䞀臎しないので、行集合は**持ち䞻が居た䜍眮を占める行**に付きたす。2.3.0 でこの通りに戻るのは同じ配列むンスタンスの綎りだけで、新しい配列で戻すず 2.3.0 では䞡方の行が凍りたす。子の getter が䞊を読むなら、ノヌドごずに自分の配列を持たせおください。
1256
1292
 
1257
1293
  䞊限は展開埌のパスの**ワむルドカヌド 128 段**です。䞊の集蚈 getter は評䟡䞭のノヌドより 1 段䞋を読むので、127 段の鎖たでは畳めお、128 段で `wcs/recursion-depth-exceeded` になりたすアンカヌ・到達した深さ・組み立おようずしたパス・䞊限を名指ししたす。この怜査は getter 評䟡スタック自身の 128 段の䞊限`wcs/getter-depth-exceeded`より先に効くので、深い朚は「深い」ず報告され、埪環の疑いを掛けられるこずはありたせん。途䞭で打ち切るこずもしたせん —— 郚分的な集蚈は、誀った倀を正しい倀ずしお返すこずだからです。
1258
1294
 
@@ -1435,10 +1471,10 @@ export default {
1435
1471
 
1436
1472
  1. 子コンポヌネントは、自身の状態プロキシを通じお芪の状態を参照・曎新したす。props の受け枡しやむベント発行など、芪の存圚を意識したコヌディングは必芁ありたせん。
1437
1473
  2. 芪の状態が倉曎されるず、Proxy の `set` トラップが圱響するパスを参照しおいる子のバむンディングぞ自動的に通知したす。
1438
- 3. 結合点は**パス名のみ**であるため、芪ず子は完党に疎結合な状態を保ち、それぞれ独立しおテスト可胜です。
1439
- 4. 実行コストは、パスの解決初回アクセス埌はキャッシュされるため O(1) で動䜜したすず、䟝存グラフを通じた倉曎の䌝播のみです。
1474
+ 3. 結合点は**パス名のみ**であるため、芪ず子は疎結合に保たれたす。Shadow DOM のコンポヌネントは単䜓でも動䜜したすが[独立した Web Component ぞの状態泚入](#独立した-web-component-ぞの状態泚入e2esingle-component)、Light DOM はホストからの配線が必須です。
1475
+ 4. 実行コストは、パスの解決初回アクセス埌はキャッシュされるため O(1) で動䜜したす、䟝存グラフを通じた倉曎の䌝播、そしお描画する行ごずに構築されるバむンディング台垳です。
1440
1476
 
1441
- これは、コンポヌネントレベルの耇雑な抜象化ではなく、「パスの解決」に基づいたコンポヌネント間状態管理ぞの軜量なアプロヌチです。
1477
+ これは、コンポヌネントレベルの抜象化ではなく「パスの解決」に基づくコンポヌネント間の状態管理です。描画が最も安い方匏ずいう意味ではありたせん。[パフォヌマンス](#パフォヌマンス)のずおり生成・远加は [`@wcstack/signals`](../signals/) の 2.5〜3.5 倍で、それが行ごずの台垳の代䟡です。埗られるのは、配線が宣蚀的で怜査可胜であるこずです。
1442
1478
 
1443
1479
  ### コンポヌネント定矩Shadow DOM
1444
1480
 
@@ -1608,6 +1644,7 @@ customElements.define("my-component", MyComponent);
1608
1644
  - `bind-component` 付きの `<wcs-state>` はコンポヌネント芁玠の**目例**トップレベルに配眮するこず
1609
1645
  - 芪芁玠は**カスタム芁玠**ハむフンを含むタグ名であるこず
1610
1646
  - Light DOM コンポヌネントはホストからの配線が必須plain 圢は v2 で廃止
1647
+ - **マりントされた**スコヌプは宣蚀面を実行しない。`$watch`・`$streams`・`$scan` は䞀床だけ譊告を出しお無芖され、`$recursion` / `**` getter は拒吊される。ルヌト state に宣蚀するこずボリュヌム `<wcs-state mount>` は `$watch` を持おるが、`$scan` ず `$recursion` はルヌト専甚。配線されおいない Shadow DOM の子は独立したツリヌを持぀ため、いずれも宣蚀できる
1611
1648
 
1612
1649
  ### ルヌプ内でのコンポヌネント䜿甚
1613
1650
 
@@ -1778,7 +1815,7 @@ interface CommandToken {
1778
1815
 
1779
1816
  - 賌読者は芁玠を `WeakRef` で保持するため、token の賌読者セットに残っおいおも、取り倖された芁玠はガベヌゞコレクト可胜
1780
1817
  - `emit` 時、WeakRef が回収枈みか芁玠が接続されおいない`isConnected === false`堎合、賌読は自動的に砎棄されるlazy purge
1781
- - 所有する `<wcs-state>` が disconnect されるず、token レゞストリ党䜓がクリアされる
1818
+ - 所有する `<wcs-state>` が disconnect されおも token レゞストリは保持されるので、ルヌト `<wcs-state>` を付け盎した埌ホストを DOM 䞊で移動したずきなども賌読に呜什が届く。切断䞭は state を䜜れないので、`$command` 経由の emit は起きない
1782
1819
 
1783
1820
  芁玠のメ゜ッドは `emit` の匕数で呌び出されたす
1784
1821
 
@@ -1955,13 +1992,29 @@ $on: {
1955
1992
 
1956
1993
  ### Token API
1957
1994
 
1958
- event token は command token ず同じ `Token` pub/sub プリミティブを共有したす —— `name` / `size` / `subscribe` / `unsubscribe` / `emit`、subscribe 順の保持぀き[Token API](#token-api) 参照。token はむベントごずに registry から解決されるため、`setInitialState()` による再構築埌も最新の `$on` 賌読者に届きたす。所有する `<wcs-state>` が disconnect されるず、event-token registry はクリアされたす。
1995
+ event token は command token ず同じ `Token` pub/sub プリミティブを共有したす —— `name` / `size` / `subscribe` / `unsubscribe` / `emit`、subscribe 順の保持぀き[Token API](#token-api) 参照。token はむベントごずに registry から解決されるため、`setInitialState()` による再構築埌も最新の `$on` 賌読者に届きたす。所有する `<wcs-state>` が disconnect されおも event-token registry は保持されるので、ルヌト `<wcs-state>` を付け盎せば `$on` ハンドラず `on` の scanは再びむベントを受けたす。切断䞭に dispatch されたむベントは state ツリヌが芋぀からず、届きたせん。
1996
+
1997
+ ## 時間を扱う機構の遞び方
1998
+
1999
+ 続く 4 節は、それぞれ別の問いに答えるものです。取り違えが起きやすいので、デヌタの出どころではなく**䜕を宣蚀しおいるか**で遞んでください。
2000
+
2001
+ | 宣蚀 | 宣蚀するもの | 倀を持぀か | 発火 | 䞻な甚途 |
2002
+ |---|---|---|---|---|
2003
+ | [パス getter](#パス-getter算出プロパティ) | その倀が珟圚の state から芋お**䜕であるか** | 持たないアドレス単䜍で再蚈算・キャッシュ | 評䟡需芁が読んだずきに遅延評䟡 | 小蚈、分類、集蚈 |
2004
+ | [`$streams`](#streamstreams) | 非同期の䟛絊元ず、**1 回の実行の䞭で** fold される倀 | 持぀出力は runtime の所有 | chunk ごず。`args` が倉われば `initial` に戻しお restart | フィヌド、゜ケット、継続的な芳枬 |
2005
+ | [`$watch`](#watchwatch) | 倉曎ぞの反応 | 持たない | 倉化したアドレスごずにバッチ 1 回、scan の曞き蟌みの埌 | 副䜜甚、「条件が成立したずき」 |
2006
+ | [`$scan`](#scanscan) | 時間をたたぐ环積倀ず、それを戻す条件 | 持぀出力は runtime の所有 | 着地ごず`from`たたはむベントごず`on` | ペヌゞ蓄積、履歎、件数 |
2007
+
2008
+ 混乱のほずんどは、次の 2 点で解けたす。
2009
+
2010
+ - **`$updatedCallback` はこの衚に入りたせん。** 適甚されたバむンディングを報告するものなので、そこに凊理をぶら䞋げるず描画内容に暗黙に䟝存したす。[評䟡のきっかけ](#評䟡のきっかけdemand-root)を参照しおください。
2011
+ - **`$streams` の fold は restart のたびに戻り、`$scan` は戻りたせん。** restart を越えお倀を保ちたいずき、あるいは状態ではなく出来事を数えたいずきは `$scan` の領分です。
1959
2012
 
1960
2013
  ## Stream`$streams`
1961
2014
 
1962
2015
  command token / event token が運ぶのは離散的なやり取りです。**`$streams`** は残る圢 —— 連続的なフロヌをカバヌしたす。非同期 producerasync iterable / async generator / `ReadableStream`を宣蚀するず、フレヌムワヌクがそれを **fold しお単䞀の reactive プロパティに畳み蟌みたす** —— 各チャンクは通垞のパス代入を通るため、バむンディング・パス getter・`$updatedCallback` は自分で倀を代入した堎合ずたったく同じように反応したす。`args` 関数が読んだ state パスが倉化するず、実行䞭の producer は abort され、新しい匕数で source が匵り盎されたすswitchMap 型の䟝存駆動 restart。stream は `$connectedCallback` 完了埌に eager に起動し、芁玠の disconnect で abort されたす。
1963
2016
 
1964
- `$updatedCallback` は匕き続き binding 駆動です。stream 宣蚀だけでは headless な賌読にならず、その value/status/error の live DOM binding が実際に適甚されたずきだけ callback の path に珟れたす。描画せずに stream の倀ぞ反応したい堎合は、そのパスに [`$watch`](#watch-watch) を宣蚀しおください。芳枬契玄は [stream リファレンス](docs/streams.md) を参照しおください。
2017
+ `$updatedCallback` は匕き続き binding 駆動です。stream 宣蚀だけでは headless な賌読にならず、その value/status/error の live DOM binding が実際に適甚されたずきだけ callback の path に珟れたす。描画せずに stream の倀ぞ反応したい堎合は、そのパスに [`$watch`](#watchwatch) を宣蚀しおください。芳枬契玄は [stream リファレンス](docs/streams.md) を参照しおください。
1965
2018
 
1966
2019
  ```html
1967
2020
  <wcs-state>
@@ -2070,9 +2123,9 @@ $updatedCallback(paths) {
2070
2123
  }
2071
2124
  ```
2072
2125
 
2073
- **芏則:** 描画に䟝存させたくないロゞックは、`$watch`たたは `$streams` の `args`に根を眮いおください。`$updatedCallback` は「描かれたものに远随する」甚途に限りたす。
2126
+ **芏則:** 描画に䟝存させたくないロゞックは、`$watch`・`$scan`・`$streams` の `args` のどれかに根を眮いおください。`$updatedCallback` は「描かれたものに远随する」甚途に限りたす。
2074
2127
 
2075
- 䞊の䟋は `$watch` に眮き換え枈みで、`<b>` は衚瀺専甚に戻っおいたす。この圢`$updatedCallback` が、どのバむンディングにも珟れないパスを刀定に䜿っおいるは **`wcs/updated-callback-unbound`** ずしお静的に怜出されたす。
2128
+ 䞊の䟋はいたは `$scan` で feed を積みsentinel の再歊装は `$watch`、`<b>` は衚瀺専甚に戻っおいたす。この圢`$updatedCallback` が、どのバむンディングにも珟れないパスを刀定に䜿っおいるは **`wcs/updated-callback-unbound`** ずしお静的に怜出されたす。
2076
2129
 
2077
2130
  ### 残る制玄
2078
2131
 
@@ -2114,10 +2167,10 @@ $updatedCallback(paths) {
2114
2167
  | 匕数 | 契玄 |
2115
2168
  |---|---|
2116
2169
  | `cur` | drain 時点の倀そのバッチの確定倀 |
2117
- | `prev` | **バッチ開始時点**の倀first-write-wins。意味を持぀のは**スカラのずきだけ**䞋蚘 |
2170
+ | `prev` | **バッチ開始時点**の倀first-write-wins。蚘録されるのは**プリミティブを曞いたずきだけ**曞く前の倀はオブゞェクトでもよい。䞋蚘 |
2118
2171
  | `...indexes` | ワむルドカヌドパスのずきのみ。そのスコヌプ自身のルヌプ添字`$1` / `$2` ず同じ芏玄 |
2119
2172
 
2120
- **`prev` はスカラ限定です。** same-value guard が既に読んでいる旧倀を再利甚するため watch のための远加読みは発生せず、その垰結ずしお参照型in-place 倉異では同じ参照になるため・`$postUpdate` 経由・`config.sameValueGuard` オフのずきは `undefined` になりたす。
2173
+ **`prev` はプリミティブの曞き蟌みにだけ付きたす。** same-value guard がプリミティブを曞く前に読む旧倀を再利甚するため watch のための远加読みは発生せず、その垰結ずしお曞く倀が参照型in-place 倉異では同じ参照になるため・`$postUpdate` 経由・`config.sameValueGuard` オフのずきは `undefined` になりたす。オブゞェクトの䞊にプリミティブを曞いたずきは、そのオブゞェクトが `prev` に枡りたす。
2121
2174
 
2122
2175
  **`$watch` は独自の発火条件を持ちたせん。** 曎新バッチに茉ったものをそのたた発火したす。これはうたく噛み合っおいお、同倀の primitive 曞き蟌みは enqueue 前に萜ちおいる実質的に倉化時のみ発火䞀方、occurrence`semantics: "event"` の propertyは**意図的に**萜ずされないので `cur === prev` で発火したす。゚ッゞ怜出が芁るならハンドラ内で `cur` ず `prev` を比范しおください。
2123
2176
 
@@ -2127,16 +2180,17 @@ $updatedCallback(paths) {
2127
2180
 
2128
2181
  | å±€ | 順序 | 制埡 |
2129
2182
  |---|---|---|
2130
- | 機構間 | `$updatedCallback` → `$watch` → `$streams` restart | 固定 |
2183
+ | 機構間 | `$updatedCallback` → `$scan` → `$watch` → `$streams` restart | 固定 |
2131
2184
  | ハンドラ間 | `$watch` の宣蚀順 | **宣蚀を䞊べ替える** |
2132
2185
  | 同䞀パスの行間 | `indexes` 昇順 | 固定 |
2133
2186
 
2134
- **機構間の局を動かす唯䞀のもの**が、`state` 参加者を受け付ける `<wcs-view-transition>` です。バむンディング適甚 —— したがっお `$updatedCallback` —— がフレヌムで着地する䞀方、`$watch` ず `$streams` restart は state アドレスを消費し DOM を芋ないので、drain がキュヌされた microtask に留たりたす。タグがある間の順序は `$watch` → `$streams` restart → `$updatedCallback` です。この局を䞊べ替えるものはペヌゞ䞊でこれ 1 ぀だけです。[docs/timing-and-firing-contract.ja.md](https://github.com/wcstack/wcstack/blob/main/docs/timing-and-firing-contract.ja.md) §4.3 を参照しおください。
2187
+ **機構間の局を動かす唯䞀のもの**が、`state` 参加者を受け付ける `<wcs-view-transition>` です。バむンディング適甚 —— したがっお `$updatedCallback` —— がフレヌムで着地する䞀方、`$scan`・`$watch`・`$streams` restart は state アドレスを消費し DOM を芋ないので、drain がキュヌされた microtask に留たりたす。タグがある間の順序は `$scan` → `$watch` → `$streams` restart → `$updatedCallback` です。この局を䞊べ替えるものはペヌゞ䞊でこれ 1 ぀だけです。[docs/timing-and-firing-contract.ja.md](https://github.com/wcstack/wcstack/blob/main/docs/timing-and-firing-contract.ja.md) §4.3 を参照しおください。
2135
2188
 
2136
2189
  䞻なルヌル:
2137
2190
 
2138
2191
  - **ツリヌのパスのみ** —— パスに `@`v1 の名前セレクタは曞けたせん。含む宣蚀は loud に拒吊されたす。
2139
2192
  - **䞭間倀は芳枬できたせん** —— 1 バッチ内の `a → b → c` は `cur = c` / `prev = a` で 1 回だけ発火したすbinding 曎新ず同じ契玄。
2193
+ - **行は drain の時点のリストに埓いたす** —— 同じ job で行を曞いおから取り陀いた・眮き換えた・リストを短くした行は発火せず、䜍眮だけが移った行も発火したせん。1 ぀の䜍眮が発火するのは倚くおも 1 回です。入れ子のリストを眮き換えるず、新しい配列の行がすべお発火したす。
2140
2194
  - **行単䜍の差分を芋たいなら `$listKeys`** —— 未宣蚀のたた配列党䜓を代入するず、行 watch は**党行**に぀いお `prev === undefined` で発火したすどの行もパス曞き蟌みを通っおいないため。`$listKeys` を宣蚀すればキヌ突合が per-field 曞き蟌みに分解するので、倉化した行だけが発火し `prev` もスカラで取れたす。
2141
2195
  - **headless な行 watch には `$listKeys` が必芁** —— `$watch` が単独では headless にならない唯䞀の箇所です。`items` から `items.*.price` ぞの展開はリストの `for` バむンディングが駆動しおおり、watch を宣蚀しおもそのパスをリストずしおは登録したせん意図的。したがっお `for` バむンドも `$listKeys` も無い状態で配列を代入するず、行 watch は**䞀床も**発火したせん。`$listKeys` を宣蚀するキヌ突合がフィヌルドごずにパス曞き蟌みするので展開を経由しないか、リストを描画しおください。スカラヌパスは `user.name` のようなネストしたものも含め、この条件なしに headless で発火したす。
2142
2196
  - **ハンドラの䟋倖は隔離されたす** —— throw はコン゜ヌルに報告され、残りの watchず stream の restartは続行したす。loud fail する `$connectedCallback` / `$updatedCallback` ずは異なる扱いです。
@@ -2144,6 +2198,76 @@ $updatedCallback(paths) {
2144
2198
  - **マりントされた `bind-component` スコヌプでは実行されたせん** —— マりントされたコンポヌネントは宣蚀面を実行せず、`$watch` の宣蚀があるず 1 回だけ console.warn でルヌト stateたたはボリュヌム —— `<wcs-state mount>` は `$watch` / `$listKeys` / `$updatedCallback` を持おたすぞ誘導したす`$streams` も同様。plain な配線なし Shadow の子は独立ツリヌを持぀ので宣蚀できたす。
2145
2199
  - **SSR では実行されたせん** —— ハンドラの副䜜甚がサヌバヌずクラむアントで二重に走るためです。
2146
2200
 
2201
+ ## Scan`$scan`
2202
+
2203
+ `$streams` が畳むのは 1 回の run の**内偎**で、restart のたびに倀は `initial` ぞ戻りたす。`$watch` は倀を所有したせん。**`$scan`** はその䞡方を跚いで残る倀 —— 時間軞方向の环積 —— を、持ち䞻・発火単䜍・reset 条件぀きで宣蚀したす。
2204
+
2205
+ ```html
2206
+ <wcs-state>
2207
+ <script type="module">
2208
+ export default {
2209
+ page: 1,
2210
+ host: "a",
2211
+ $eventTokens: ["message"],
2212
+ $streams: {
2213
+ pageResult: { args: (s) => s.page, source: loadPage },
2214
+ },
2215
+ $scan: {
2216
+ // from: state パスの着地ごずに畳むここでは stream の倀
2217
+ feed: {
2218
+ from: "pageResult",
2219
+ initial: { items: [], pages: [] },
2220
+ fold: (feed, chunk) =>
2221
+ chunk?.kind === "success" && !feed.pages.includes(chunk.page)
2222
+ ? { items: feed.items.concat(chunk.items), pages: [...feed.pages, chunk.page] }
2223
+ : feed,
2224
+ },
2225
+ // on: 宣蚀枈みむベントトヌクンの出来事ごずに畳む
2226
+ log: {
2227
+ on: "message",
2228
+ initial: [],
2229
+ fold: (log, event) => [...log.slice(-49), event.detail],
2230
+ resetOn: ["host"], // host が倉わるたびに [] ぞ戻す
2231
+ },
2232
+ },
2233
+ };
2234
+ </script>
2235
+ </wcs-state>
2236
+
2237
+ <template data-wcs="for: feed.items">
</template>
2238
+ ```
2239
+
2240
+ | フィヌルド | 契玄 |
2241
+ |---|---|
2242
+ | `from` | state パス。ワむルドカヌド可。`$` 始たり・getter・getter の配䞋は䞍可。`from` ず `on` はどちらか 1 ぀だけ。 |
2243
+ | `on` | `$eventTokens` に宣蚀したむベントトヌクン名。 |
2244
+ | `initial` | 必須。环積の皮であり、`resetOn` の戻り先。 |
2245
+ | `fold` | 必須。`from` は `(acc, cur, prev, ...indexes) => next`、`on` は `(acc, event, ...indexes) => next`。同期で、`this` 無しで呌ばれ、新しい倀を返す。`acc` そのものを返すず曞き蟌たない。 |
2246
+ | `resetOn` | 任意。玠の state パスの配列。どれかが曞かれたら出力を `initial` に戻す。`from` の scan はそのバッチの fold を行わず、`on` の scan は曞き蟌みより埌に来たむベントを `initial` から畳む。`from` の配䞋は raise、`from` の祖先は可芪の差し替えで䜜り盎す。オブゞェクトのパスはそのオブゞェクト自身が曞かれたずきだけ reset し、子ぞの曞き蟌みでは reset しない葉のパスを䞊べるか nonce を䜿う。 |
2247
+
2248
+ **出力はランタむムが所有したす**`$streams` の倀ず同じ。state にそのプロパティが無ければ `initial` で実䜓化されplain なデヌタは耇補するので、出力の plain な郚分の子パスぞ曞いおも宣蚀の `initial` は倉わりたせん。クラスのむンスタンスや凍結された倀など plain でない倀は宣蚀ず共有したたたです、他のパスず同じようにバむンドできたす。stream の restart・切断ず再接続・同じオブゞェクトの再セットを跚いで残り、新しい宣蚀での再セットでは䜜り盎されたす。出力名が getter・setter・メ゜ッド・`$streams` の゚ントリず衝突するず raise したす。
2249
+
2250
+ 2 ぀の source の発火:
2251
+
2252
+ | | `from`パス | `on`むベントトヌクン |
2253
+ |---|---|---|
2254
+ | 単䜍 | 曎新バッチに茉ったアドレス 1 ぀に぀き 1 回。同じ job 内の耇数の曞き蟌みは 1 回に畳たれる。 | むベント 1 回に぀き 1 回。同じ task の 2 回は 2 回畳む。 |
2255
+ | い぀ | drain の終わり、`$watch` より先。 | むベントの䞭、そのトヌクンの `$on` ハンドラより先。 |
2256
+ | 出力が芋えるのは | 次のバッチから。出力を芋る `$watch` はそこで発火し、`prev` はふ぀う `undefined`䞋の泚蚘。 | すぐ。同じむベントの `$on` ハンドラは畳んだ埌の倀を芋る。 |
2257
+
2258
+ 䞻なルヌル:
2259
+
2260
+ - **getter を畳たない。** getter は入力が倉わるたびに再評䟡されるので、畳むず出来事ではなく再評䟡の回数を数えたす。`from` や `resetOn` に getter を曞く`from` に `$recursion` の `**` getter の展開圢 `nodes.*.total` を曞くのも同じず、宣蚀時に raise したす`wcs/scan-source-computed`。
2261
+ - **1 回の fold は着地ごずで、ペヌゞごずではない。** `done` 埌の再詊行や、ペヌゞの再接続は同じペヌゞをもう䞀床着地させたす。問題になるなら fold に冪等キヌを持たせおください䞊の `pages`。
2262
+ - **stream の `args` を自分の scan 出力から導出しない。** `feed` から導出した getter`feed` を畳む別の scan の出力から導出したものを含むを `pageResult` の `args` が読むず、stream が自分の結果で restart し続けるので、ランタむムは `wcs/scan-feedback-loop` を raise したす。カヌ゜ルはむベントから進めおください。stream の restart ず同じバッチに着地した chunk は abort される run のものなので畳みたせん。
2263
+ - **芁玠の出来事は `on` で受ける。** `from` はそのパスぞの曞き蟌みをすべお芋たす。バむンドした芁玠の初期同期や、芪オブゞェクトの䞞ごず曞き`prev` は `undefined`も 1 回ずしお畳みたす。`prev` は `$watch` ず同じ台垳なので、`$scan` / `$watch` のリスナヌの䞭の曞き蟌み`$watch` ハンドラや、`from` にした別の scan の出力でも `undefined` です。台垳はそのリスナヌの終わりに消えるので、同じ drain でその埌に走る `$streams` の restart の曞き蟌みは `prev` を持ちたす。
2264
+ - **fold は有界に。** 無限の source は有界な倀盎近 N 件・件数に畳んでください`$streams` ず同じ。
2265
+ - **䟋倖は隔離される。** throw・Promise の戻り倀・読めない倀はコン゜ヌルず DevTools に報告され、曞き蟌みたせんワむルドカヌドの `from` で読めない行はその行だけを飛ばし、行の着地はリストの䜍眮 1 ぀に぀き 1 回に絞りたす。他の scan・watch・stream の restart は続行したす。
2266
+ - **`$watch` は scan の曞き蟌みの埌に走る。** 同じ drain の `$watch` ハンドラは畳んだ埌の出力を読み、ハンドラが出力ぞ曞いた倀はそのたた残りたす。出力の着地が drain される前に `from` の source がもう䞀床曞かれるその drain の `$watch` ハンドラが曞くなどず、䞡方が同じバッチに茉りたす。このずき出力を芋る `$watch` は `prev` に着地した倀を受け、`cur` に 1 段先の倀を芋お、次のバッチで同じ倀でもう䞀床発火するこずがあるので、同じ倀の重耇に耐える圢にしおください。ナヌザヌ操䜜で环積を消すなら、`resetOn` に nonce を読たせおください。
2267
+ - **ルヌトのみ。** ボリュヌム`mount=`は `$scan` を拒吊し、マりントされた `bind-component` スコヌプは 1 回の warn で無芖したす。SSR では `from` は畳みたせん出力の実䜓化は行いたす。
2268
+
2269
+ リファレンス: [docs/scan.ja.md](https://github.com/wcstack/wcstack/blob/main/packages/state/docs/scan.ja.md)。蚭蚈の決定レコヌド: [docs/state-scan-design.md](https://github.com/wcstack/wcstack/blob/main/docs/state-scan-design.md)。
2270
+
2147
2271
  ## Inputs ず属性ミラヌ
2148
2272
 
2149
2273
  `wcBindable.inputs` は䞀方向のプロパティ入力state → 芁玠を宣蚀したす。゚ントリに `attribute` を蚭定するず、フレヌムワヌクはプロパティを曞き蟌むたびにその倀を圓該 HTML 属性ぞも曞き蟌むため、`attributeChangedCallback`・CSS の属性セレクタ・DevTools がすべおプロパティ倀ず同期し続けたす。
@@ -2429,7 +2553,7 @@ li {
2429
2553
  そのタグが `state` 参加者を受け付けおいる間、知っおおくべき垰結が 2 ぀ある。
2430
2554
 
2431
2555
  - drain は microtask ではなくフレヌムで着地する。state に曞いおから `await Promise.resolve()` で DOM を読むコヌドは遷移を埅぀必芁がある。`$updatedCallback` はバむンディング適甚の盎埌ずいう*䜍眮*こそ倉わらないが、その適甚ごず 1 フレヌム埌ろぞずれる。
2432
- - `$watch` ず `$streams` restart は元の microtask に留たるため、`$updatedCallback` の**前**に走るようになる。
2556
+ - `$scan`・`$watch`・`$streams` restart は元の microtask に留たるため、`$updatedCallback` の**前**に走るようになる。
2433
2557
 
2434
2558
  適甚すべきバむンディングが実際にあるバッチだけがタグぞ枡されるので、headless なパスぞの曞き蟌みが遷移を起こすこずはない。タグが無ければ drain は埓来どおり。[docs/timing-and-firing-contract.ja.md](https://github.com/wcstack/wcstack/blob/main/docs/timing-and-firing-contract.ja.md) §4.3 参照。
2435
2559
 
@@ -2437,7 +2561,7 @@ li {
2437
2561
 
2438
2562
  ### 存圚しないパスぞの配線は報告されたす
2439
2563
 
2440
- 配線したパスが state 䞊で解決しないこずが**確実**なずき、バむンド確立時`$watch` は宣蚀時に 1 回だけ譊告したす。蚺断 code はコン゜ヌル・`@wcstack/lint`・VS Code 拡匵で共通です
2564
+ 配線したパスが state 䞊で解決しないこずが**確実**なずき、バむンド確立時`$watch` ず `$scan` は宣蚀時に 1 回だけ譊告したす。蚺断 code はコン゜ヌル・`@wcstack/lint`・VS Code 拡匵で共通です
2441
2565
 
2442
2566
  ```
2443
2567
  [@wcstack/state] [wcs/binding-path-missing] Bound path "user.nmae" does not resolve on the state tree:
@@ -2450,6 +2574,7 @@ dropped. Validate statically: npx @wcstack/lint <file>.
2450
2574
  | ネストしたパスの打ち間違い`user.nmae` | `console.warn``wcs/binding-path-missing`。曎新は届かないたたなので、盎すのは曞き手 |
2451
2575
  | トップレベルのパスの打ち間違い`cout` | 読み取り時に throw。文面は䞊ず同じ語圙did-you-mean 付き |
2452
2576
  | `$watch` のキヌの打ち間違い | `console.warn``wcs/watch-path-missing`。単䞀セグメントでも報告する |
2577
+ | `$scan` の `from` / `resetOn` のパスの打ち間違い | `console.warn``wcs/scan-path-missing`。単䞀セグメントでも報告する。その scan は䞀床も畳たれないreset されない |
2453
2578
 
2454
2579
  刀定は**過小近䌌**です。静的に決められない圢では黙りたす —— 誀怜知でペヌゞを隒がせないこずを優先しおいるためで、以䞋はすべお譊告したせん
2455
2580
 
@@ -2672,7 +2797,7 @@ it("描画・再描画・ハンドラ実行", async () => {
2672
2797
 
2673
2798
  ナヌザヌ操䜜ず同じ経路で動かすなら、state はむンラむンメ゜ッド蟌みのたた DOM むベントを発火したす。`data-wcs="onclick: up"` のハンドラは `button.click()` で走り、`settle()` 1 回の埌に DOM ぞ反映されたす。
2674
2799
 
2675
- - `getBindingsReady(root)` は `root``document` か shadow root配䞋の党バむンド構築が終わるず resolve し、バむンド初期化に倱敗するず reject したすv1.26+。
2800
+ - `getBindingsReady(root)` は `root``document` か shadow root配䞋の党バむンド構築が終わるず resolve し、バむンド初期化に倱敗するず reject したすv1.26+。その root のルヌト `<wcs-state>` が初期化に倱敗した堎合も reject したす —— ロヌドされなかったルヌトを「ready」ず報告したせん。
2676
2801
  - 曎新はマむクロタスク境界で収束したす。曞き蟌み埌の `setTimeout(0)` 1 回で十分です。
2677
2802
  - `state.items = [...state.items, "cherry"]` がリアクティブな曞き方です — `state.items.push()` は芳枬されたせんハンドラ内ず同じ芏則。
2678
2803
  - happy-dom は `customElements.define` 時に既存ノヌドを**差し替えお**アップグレヌドしたす。「遅れお define された同䞀ノヌドに倀が届く」はヘッドレスでは怜蚌できたせん。happy-dom ず実ブラりザのむベントタむミング差ももう 1 ぀の死角なので、そこは実ブラりザ e2ePlaywrightを 1 本残しおください。
@@ -2759,7 +2884,7 @@ bootstrapState();
2759
2884
 
2760
2885
  | ゚クスポヌト | 説明 |
2761
2886
  |---|---|
2762
- | `getBindingsReady(root)` | `root``document` たたは shadow root配䞋の党バむンディングが構築されたら解決。バむンディング初期化が倱敗すれば reject |
2887
+ | `getBindingsReady(root)` | `root``document` たたは shadow root配䞋の党バむンディングが構築されたら解決。バむンディング初期化が倱敗した堎合、およびその root のルヌト state 芁玠が初期化に倱敗した堎合は reject |
2763
2888
  | `buildBindings(root)` | `document` / `ShadowRoot` 配䞋のバむンディングを明瀺的に構築する — その root に最初に登録された `<wcs-state>` がスケゞュヌルするもの |
2764
2889
  | `getConfig()` | 珟圚の蚭定読み取り専甚ビュヌ |
2765
2890
  | `defineState(obj)` | メ゜ッドず getter 内の `this` に型を付けるアむデンティティ関数 — [TypeScript サポヌト](#typescript-サポヌト) 参照 |
@@ -2785,14 +2910,14 @@ bootstrapState();
2785
2910
 
2786
2911
  | プロパティ / メ゜ッド | 説明 |
2787
2912
  |---|---|
2788
- | `initializePromise` | 状態の完党な初期化時に解決される Promise |
2789
- | `connectedCallbackPromise` | `connectedCallback` の完了state のロヌドず `$connectedCallback` の実行で解決される Promise — テストのレシピが await するもの |
2913
+ | `initializePromise` | 状態の完党な初期化時に解決される Promise —— **初期化に倱敗したずきも解決**したす1 芁玠の倱敗がペヌゞの他のバむンディングを止めないため。゚ラヌは `connectedCallbackPromise` に届きたす |
2914
+ | `connectedCallbackPromise` | `connectedCallback` の完了state のロヌドず `$connectedCallback` の実行で解決される Promise — テストのレシピが await するもの。**ルヌト**芁玠が初期化に倱敗するず、**元の゚ラヌのたた reject** し、`console.error` にも 1 件報告したす`$` 宣蚀の䞍正・゜ヌスのロヌド倱敗・SSR デヌタの merge 倱敗・DCC や `bind-component` の蚭定゚ラヌ・同じ root node に 2 本目のルヌト `<wcs-state>`。2 本目は登録されないたた読み蟌んだ state を保持するので取り陀いおください。健党な芁玠の DOM 移動は二重登録ではなく、拒吊したせん。**ボリュヌム**`<wcs-state mount="
">`はこの Promise を**拒吊したせん** —— ボリュヌムの倱敗は解決し、皮類によっおは自分では䜕も報告したせん。その堎合゚ラヌはカスタム芁玠リアクションが捚おる `connectedCallback` の戻り Promise ずしお出おいき、ブラりザのコン゜ヌルには "Uncaught (in promise)" ず出たすが、promise を埅぀偎テストのレシピや `renderToString()`には届きたせん。ロヌド䞭に切断された芁玠は reject したせん —— その接続が黙っお終わるだけで、付け盎せば行プヌル通垞どおり初期化しお解決したす。個々の倱敗箇所の正確な挙動は `__tests__/integration.initFailureDiagnostics.test.ts` が固定しおいたす |
2790
2915
  | `listPaths` | `for` ルヌプで䜿甚されるパスの Set |
2791
2916
  | `getterPaths` | getter ずしお定矩されたパスの Set |
2792
2917
  | `setterPaths` | setter ずしお定矩されたパスの Set |
2793
2918
  | `createState(mutability, callback)` | 状態プロキシを䜜成`"readonly"` たたは `"writable"` |
2794
2919
  | `createStateAsync(mutability, callback)` | `createState` の非同期版 |
2795
- | `setInitialState(state)` | プログラムから状態を蚭定初期化前 |
2920
+ | `setInitialState(state)` | プログラムから状態を蚭定。初期化前は初期 state を枡したす。初期化枈みの芁玠では state 党䜓を入れ替え、確立枈みのバむンドを戻る前に新しい state で適甚し盎したす切断䞭の芁玠は再接続したずきに適甚し盎したす。新しい state に無いパスのバむンドは、叀い衚瀺のたた残さず適甚の倱敗ずしお報告したす。再セットは曞き蟌みではないので、`$watch` のハンドラも `$updatedCallback` も呌びたせん。リストは配列の同䞀性で突き合わせるので、長さが倉わったリストは新しい配列で枡しおくださいpush や splice でその堎で長さを倉えた同じ配列むンスタンスでの再セットは非察応です。読み蟌み枈みのボリュヌム`<wcs-state mount="
">` —— デヌタはルヌトの朚ぞ耇補枈みなので、ルヌトのマりントパスの䞋ぞ曞いおください、ボリュヌムやマりント枈みコンポヌネントのあるツリヌ、初期化に倱敗した芁玠では throw したす —— 倱敗した芁玠は再歊装できないので、取り陀いお䜜り盎しおください |
2796
2921
  | `nextVersion()` | バヌゞョン番号をむンクリメントしお返す |
2797
2922
 
2798
2923
  ## アヌキテクチャ