Flutter から移植する
この手順でできること
Section titled “この手順でできること”Flutter の Widget や RenderObject を FloatSoda に移植し、Flutter の観測できる挙動と合った状態で PR に出せます。挙動が合わない箇所を残す場合は、理由とテストつきで記録されている状態になります。手順は5つです。
- Flutter の元の実装を見つける
- どこまでそろえるかを決める
- 差異を残すなら、記録する
- Flutter のテストを FloatSoda のテストに写す
- C# として自然な書き方に置き換える
先に、移植したい部品が Flutter 由来かを確かめてください。Flutter に対応する概念がない部品は、このページの対象外です。
次の2つがそろっていれば、手順1から始められます。
- 開発環境と Flutter の参照クローンを用意しておくこと(開発環境を用意する)
- 移植の Issue を立てておくこと(コントリビューターの規約)
Flutter との差異の判断は、Issue が必須な変更に含まれます。
手順1: Flutter の元の実装を見つける
Section titled “手順1: Flutter の元の実装を見つける”移植したい部品について、対応する Widget と、関係する Element・RenderObject の定義位置を、Flutter の版とあわせて控えます。部品専用の Element や RenderObject がないときは、継承元や委譲先の定義位置を控えます。
Flutter の元の実装は、ローカルの参照クローンで引きます(CONTRIBUTING.md の「テスト観点」では ~/code_reading/flutter_reference)。Widget は packages/flutter/lib/src/widgets/、RenderObject は packages/flutter/lib/src/rendering/ にあります。Widget / Element / RenderObject の位置は、参照クローンでクラス名を検索して特定します。flutter-widget-source skill でも特定できますが、この skill は .agents/skills/ にありません。
版は、参照クローンで git rev-parse HEAD を実行して commit を控えます。
できた? Widget、Element、RenderObject の定義位置(専用の定義がなければ継承元や委譲先)と、Flutter の commit を書き出せます。
手順2: どこまでそろえるかを決める
Section titled “手順2: どこまでそろえるかを決める”Flutter 由来の Widget と RenderObject は、明示された理由がない限り、観測できる挙動に差異を作りません。そろえる対象は次のとおりです(REVIEW.md の「6. Flutter parity」)。
- プロパティの意味
- 既定値
- レイアウト
- 描画とクリップ
- ヒットテスト
- 子の扱い
- Widget の更新
- 不正・退化入力の扱い
- dirty の条件
- Element と State のライフサイクル
「実装しやすい」「こちらの方が安全」「こちらの方が自然」だけは、差異の理由になりません。Flutter を期待して書く利用者と LLM が、その差異で困るためです。
仕様が食い違うときは、次の順に従います(REVIEW.md の「3. 仕様の一次情報と優先順位」)。
- FloatSoda で明示された差異・設計判断
- Flutter の仕様・実装・公式テスト
- 既存の FloatSoda 実装(根拠になりません)
Semantics のように、すでに移植しないと決めたものは、parity を理由に破りません。
できた? 「差異なし」か「差異あり、理由は〜」を一文で言えます。差異なしなら手順4へ、差異ありなら手順3へ進みます。
Flutter 由来かどうかの判断が割れるときは、実装を始める前に Issue で基準を明示してください。
手順3: 差異を残すなら、記録する
Section titled “手順3: 差異を残すなら、記録する”差異を残すときは、次の5項目を記録します(REVIEW.md の「6. Flutter parity」)。
| 項目 | 書くこと |
|---|---|
| Flutter の挙動 | Flutter が何をするか。対応するファイルつき |
| FloatSoda の挙動 | FloatSoda が何をするか。src/ のファイルと行つき |
| 差異が必要な理由 | 手順2の「理由にならないもの」以外の理由 |
| 差異を固定するテスト | 差異を戻すと失敗するテストのファイルとメソッド名 |
| 利用者向けのドキュメント | 利用者から観測できる場合の、docs やサンプルの ## Flutterとの違い 節 |
差異を固定するテストがないと、次の移植で差異が戻されます。テストは省かないでください。
記録先は、差異の台帳 known-divergences.md です。エントリの形と、deliberate / not ported / port mistake / unlabelled のラベルの意味は、台帳の冒頭にあります。台帳を ADR にまとめる移行と、ADR の置き場所と番号の付け方は、決まっていません。決まるまでは、台帳へ追記してください。設計判断として ADR も書く場合は 決定を ADR に書く を読んでください。
台帳の Observation 欄は、差異が HMD なしで観測できるか(HEADLESS)、SteamVR が要るか(VR)を示します。HMD が要る範囲の分け方は テストの分け方 にあります。
できた? 5項目がすべて埋まり、差異を戻すと落ちるテストがあります。
手順4: Flutter のテストを FloatSoda のテストに写す
Section titled “手順4: Flutter のテストを FloatSoda のテストに写す”Flutter 由来の Widget と RenderObject のテストは、FloatSoda 独自にケースを想像するだけで済ませません(CONTRIBUTING.md の「テスト観点」)。Flutter の実装の分岐、公式テスト、API contract を確かめ、対応する重要なケースを FloatSoda 側でも検証します。Flutter が明示的にテストしている退化ケースは、FloatSoda でも壊れます。
Flutter の公式テストは、参照クローンの packages/flutter/test/widgets/ と packages/flutter/test/rendering/ にあります。FloatSoda 側のテストは、tests/FloatSoda.Test の Widgets/ と RenderObjects/ に置きます。
写したテストの名前は 対象メンバー名_条件_期待結果 の形にし、条件と期待結果を日本語で書きます(CONTRIBUTING.md の「テストの命名」)。バグ修正の場合は、修正を戻すと落ちるテストを足します。
できた? Flutter のテストのケースと、FloatSoda のテストの対応を表にできます。
手順5: C# として自然な書き方に置き換える
Section titled “手順5: C# として自然な書き方に置き換える”次の置き換えは、差異に数えません(REVIEW.md の「6. Flutter parity」)。
eventinit/requiredrecord/record struct- .NET 標準機構の利用
迷ったら、利用者から見た挙動が変わるかで切り分けます。変わらなければ置き換えです。変わるなら、手順2に戻って差異として扱います。
できた? 置き換えの前後で、観測できる挙動が同じです。
PR に書くこと
Section titled “PR に書くこと”PR の本文は、PR テンプレートの「Flutter reference」欄に次の4つを書きます。PR から、Flutter の版、参照した実装、参照したテストを追跡できるようにするためです。
- Flutter version / commit
- Referenced source
- Referenced tests
- Behavioral differences from Flutter(差異がなければ「なし(parity)」)
出す前のチェックは コントリビューターの規約 にあります。出したあとの指摘への対応は レビューの指摘を受けて直す に進んでください。
うまくいかないとき
Section titled “うまくいかないとき”Flutter とどちらを正にするか迷う
手順2に戻り、優先順位の表で確かめます。FloatSoda で明示された差異がなければ、Flutter が正です。既存の FloatSoda 実装は根拠になりません。
差異の記録の書き方が分からない
手順3の5項目と、台帳の既存エントリを見比べてください。
判断が割れるときは、Issue で相談してください。