# 機能設計書 4-computed()

## 概要

本ドキュメントは、Vue 3のリアクティビティシステムにおける`computed()` APIの機能設計を記述する。`computed()`は依存するリアクティブデータの変化に自動追従する計算済みプロパティを定義し、結果をキャッシュして効率的に提供するAPIである。

### 本機能の処理概要

`computed()`は、getter関数またはget/setオプションオブジェクトを受け取り、依存するリアクティブデータが変更された場合にのみ再計算を行うComputedRefオブジェクトを返す。計算結果はキャッシュされ、依存データに変更がなければ再計算は行われない。ComputedRefImplクラスはSubscriberインターフェースを実装し、依存Depの変更通知を受け取る仕組みになっている。

**業務上の目的・背景**：派生的な状態（フィルタリング結果、合計値、フォーマット済みテキストなど）を効率的に計算するために不可欠なAPIである。依存データが変わらない限り再計算を避けることで、パフォーマンスを最適化する。

**機能の利用シーン**：SFCコンパイルオプションの算出（sfcOptions, previewOptions）、バージョン表示文字列の生成、フォームバリデーション結果の導出、リストのフィルタリング・ソートなどに使用される。

**主要な処理内容**：
1. getter関数またはget/setオプションからgetter/setterを抽出
2. ComputedRefImplインスタンスを生成（Subscriberとして機能）
3. `.value`アクセス時にdep.track()で依存性を記録し、refreshComputed()で必要時のみ再計算
4. 依存データ変更時にnotify()でDIRTYフラグを立て、batch処理でスケジューリング
5. WritableComputedOptionsで書き込み可能なcomputedを定義可能

**関連システム・外部連携**：`@vue/reactivity`パッケージに所属。Dep/Linkベースの依存性追跡システム、effectモジュールのbatch処理、refreshComputed()による遅延評価と密接に連携する。

**権限による制御**：getter-onlyの場合はIS_READONLYフラグが設定され、書き込み不可。get/setオプションを渡した場合は書き込み可能なWritableComputedRefとなる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | App（メイン画面） | 主画面 | sfcOptions（SFCコンパイルオプション）, previewOptions（プレビューカスタマイズ）の算出 |
| 2 | Header（ナビゲーションバー） | 補助画面 | store.vueVersionからバージョン表示文字列を算出 |

## 機能種別

リアクティビティ管理 / 計算処理API

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| getterOrOptions | ComputedGetter\<T\> \| WritableComputedOptions\<T\> | Yes | getter関数またはget/setオプションオブジェクト | 関数またはget/setを持つオブジェクト |
| debugOptions | DebuggerOptions | No | onTrack/onTriggerデバッグコールバック | 開発モードのみ有効 |

### 入力データソース

APIの引数として直接渡されるgetter関数またはオプションオブジェクト。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| ComputedRef\<T\> | ComputedRef\<T\> | getter-onlyの場合。読み取り専用の計算済みRef |
| WritableComputedRef\<T, S\> | WritableComputedRef\<T, S\> | get/setオプションの場合。書き込み可能な計算済みRef |

### 出力先

呼び出し元のComposition APIコンテキストに返却。テンプレート内では自動的にアンラップされる。

## 処理フロー

### 処理シーケンス

```
1. computed(getterOrOptions, debugOptions?)が呼び出される
   └─ getterOrOptionsが関数かオブジェクトかを判定
2. getter/setterを抽出
   ├─ 関数の場合: getter = getterOrOptions, setter = undefined
   └─ オブジェクトの場合: getter = options.get, setter = options.set
3. new ComputedRefImpl(getter, setter, isSSR)を生成
   ├─ dep: new Dep(this) - 依存性管理（computedを参照）
   ├─ flags: EffectFlags.DIRTY - 初期状態はダーティ
   └─ IS_READONLY: !setter - setterがなければ読み取り専用
4. デバッグオプションの設定（開発モード）
5. ComputedRefImplインスタンスを返却
```

### フローチャート

```mermaid
flowchart TD
    A[computed getterOrOptions] --> B{isFunction?}
    B -->|Yes| C[getter = getterOrOptions]
    B -->|No| D[getter = options.get, setter = options.set]
    C --> E[new ComputedRefImpl getter, undefined, isSSR]
    D --> E
    E --> F{__DEV__ && debugOptions?}
    F -->|Yes| G[onTrack/onTrigger設定]
    F -->|No| H[ComputedRefImplを返却]
    G --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 遅延評価 | .valueアクセス時にのみ計算が実行される | 常時 |
| BR-02 | キャッシュ | 依存データに変更がなければ前回の計算結果を返す | DIRTYフラグが立っていない場合 |
| BR-03 | 読み取り専用 | getter-only computedは書き込み不可（警告） | setter未定義の場合 |
| BR-04 | globalVersionパス | リアクティブな変更がない場合はglobalVersionで高速スキップ | computed.globalVersion === globalVersionの場合 |
| BR-05 | DIRTYフラグ管理 | 依存データ変更時にDIRTYフラグが立ち、再計算が必要であることを示す | notify()呼び出し時 |
| BR-06 | Subscriber連携 | ComputedRefImplはSubscriberインターフェースを実装し、依存Depからの通知を受け取る | Depの変更通知時 |

### 計算ロジック

- refreshComputed()による計算フロー:
  1. DIRTYフラグまたはTRACKINGフラグの状態を確認
  2. globalVersionによる高速パスチェック
  3. isDirty()で依存Depのversion変更を確認
  4. getter関数を実行し、前回値との比較（hasChanged）
  5. 変更があればdep.version++して購読者に通知

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 開発者警告 | getter-only computedへの書き込み | `Write operation failed: computed value is readonly` |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- globalVersionによる高速パスで不要な再計算を回避
- isDirty()チェックで依存Depのversionを効率的に比較
- 遅延評価により、.valueアクセスがない限り計算を実行しない

## セキュリティ考慮事項

特になし

## 備考

- ComputedRefImplはSubとDepの双方の役割を持つ（依存するDepを追跡しつつ、自身もDepとして購読者に通知する）
- SSRモードではrender effectがないため、常に再評価が行われる
- `effect`プロパティは後方互換性のために自身への参照を保持する
- デバッグモードではonTrack/onTriggerコールバックで依存性追跡の詳細を確認可能

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | computed.ts | `packages/reactivity/src/computed.ts` | ComputedRef, WritableComputedRef型定義（27-41行目） |
| 1-2 | computed.ts | `packages/reactivity/src/computed.ts` | ComputedRefImplクラスのフィールド定義（47-98行目）。deps, depsTail, flags等 |
| 1-3 | effect.ts | `packages/reactivity/src/effect.ts` | Subscriberインターフェース（58-83行目）。ComputedRefImplが実装 |

**読解のコツ**: ComputedRefImplはSubscriberとDepの両方の性質を持つ特殊なクラス。deps/depsTailは自身が依存するDepへのリンク（Subscriberとして）、dep（Depインスタンス）は自身の購読者を管理する。この二重の役割を意識して読む。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | computed.ts | `packages/reactivity/src/computed.ts` | computed()関数（189-221行目）。オーバーロードと実装 |

**主要処理フロー**:
1. **198-211行目**: getter/setterの抽出。isFunction判定で関数かオプションオブジェクトかを分岐
2. **213行目**: `new ComputedRefImpl(getter, setter, isSSR)`でインスタンス生成
3. **215-218行目**: 開発モードでのonTrack/onTriggerデバッグオプション設定

#### Step 3: ComputedRefImplの動作を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | computed.ts | `packages/reactivity/src/computed.ts` | get value()（131-145行目）。dep.track() + refreshComputed() |
| 3-2 | computed.ts | `packages/reactivity/src/computed.ts` | set value()（147-153行目）。setter呼び出しまたは警告 |
| 3-3 | computed.ts | `packages/reactivity/src/computed.ts` | notify()（117-129行目）。DIRTYフラグ設定とbatch処理 |

#### Step 4: refreshComputed()を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | effect.ts | `packages/reactivity/src/effect.ts` | refreshComputed()（365-419行目）。遅延評価と値比較のコアロジック |

**主要処理フロー**:
- **366-371行目**: TRACKINGかつ非DIRTYの場合はスキップ
- **376-378行目**: globalVersion高速パスチェック
- **387-393行目**: isDirty()チェック。依存Depのversion比較
- **402-409行目**: getter実行、hasChangedで値比較、変更時はdep.version++

### プログラム呼び出し階層図

```
computed(getterOrOptions)
    |
    +-- new ComputedRefImpl(getter, setter, isSSR)
            |
            +-- new Dep(this)    // 自身をcomputedとして設定
            |
            +-- [.value getter]
            |       +-- dep.track()           // 依存性追跡
            |       +-- refreshComputed(this) // 遅延評価
            |               |
            |               +-- globalVersion比較 (高速パス)
            |               +-- isDirty(this)
            |               |       +-- link.dep.version比較
            |               |       +-- refreshComputed(nested computed)
            |               |
            |               +-- getter(oldValue)  // 再計算実行
            |               +-- hasChanged(value, _value)
            |               +-- dep.version++     // 購読者に通知
            |
            +-- [.value setter]
            |       +-- setter(newValue) or warn
            |
            +-- [notify()]
                    +-- flags |= DIRTY
                    +-- batch(this, true)
```

### データフロー図

```
[入力]                        [処理]                            [出力]

getter: () => T      ───>  computed(getter)              ───>  ComputedRef<T>
                               |
                        ComputedRefImpl生成
                               |
                        +------+------+
                        |             |
                   .value GET    依存Dep変更
                        |             |
                   refreshComputed  notify()
                        |             |
                   getter実行     DIRTYフラグ
                        |             |
                   結果キャッシュ  batch処理
                        |
                   _value返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| computed.ts | `packages/reactivity/src/computed.ts` | ソース | computed()のメイン実装。ComputedRefImplクラス |
| effect.ts | `packages/reactivity/src/effect.ts` | ソース | refreshComputed()、Subscriberインターフェース、batch() |
| dep.ts | `packages/reactivity/src/dep.ts` | ソース | Dep/Linkクラス。依存性追跡とトリガーの中核 |
| constants.ts | `packages/reactivity/src/constants.ts` | ソース | ReactiveFlags定義 |
| index.ts | `packages/reactivity/src/index.ts` | ソース | パッケージエクスポート定義 |
