# 機能設計書 68-generateCodeFrame()

## 概要

本ドキュメントは、Vue 3の`@vue/shared`パッケージが提供する`generateCodeFrame()`関数の設計仕様を記述する。この関数は、エラーメッセージに添えるソースコード位置表示（コードフレーム）を生成する開発者向けユーティリティである。

### 本機能の処理概要

`generateCodeFrame()`は、ソースコード文字列とエラー位置（開始・終了オフセット）を入力として受け取り、エラー箇所を視覚的に示すコードフレーム（行番号付きソースコードとキャレット`^`によるアンダーライン表示）を生成する。テンプレートコンパイラや@vue/compatのエラー出力で使用される。

**業務上の目的・背景**：Vue 3のテンプレートコンパイラは、テンプレート構文エラーや警告を検出した際に、開発者にわかりやすいエラーメッセージを提供する必要がある。コードフレームはエラー箇所の前後数行のソースコードを行番号付きで表示し、問題箇所を`^`記号でハイライトすることで、開発者がエラーの原因を迅速に特定できるようにする。

**機能の利用シーン**：
- テンプレートコンパイルエラー発生時のエラーメッセージ生成
- SFCコンパイル時の構文エラー表示
- @vue/compat（互換モード）でのコンパイルエラー表示
- Explorer（コンパイラエクスプローラ画面）でのエラー表示

**主要な処理内容**：
1. 入力ソースコードを改行で行に分割する（`\r\n`と`\n`の両方に対応）
2. エラー開始位置を含む行を特定する
3. その行の前後`range`行（デフォルト2行）を含むコンテキストを生成する
4. 行番号をフォーマットして各行に付加する
5. エラー箇所にキャレット（`^`）によるアンダーラインを生成する
6. 複数行にまたがるエラーの場合、各行にアンダーラインを生成する

**関連システム・外部連携**：`@vue/compiler-core`、`@vue/compiler-sfc`、`@vue/compiler-dom`から利用される。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 4 | Index（メイン画面） | 補助機能 | コンパイルエラー発生時のソースコード位置表示 |

## 機能種別

開発者向けエラー表示ユーティリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| source | `string` | Yes | ソースコード文字列 | - |
| start | `number` | No | エラー開始位置のオフセット（0始まり）。デフォルト0 | 0以上source.length以下にクランプ |
| end | `number` | No | エラー終了位置のオフセット。デフォルトsource.length | 0以上source.length以下にクランプ |

### 入力データソース

テンプレートコンパイラのエラーオブジェクト（`CompilerError`）の`loc.start.offset`と`loc.end.offset`から取得。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | `string` | 行番号付きソースコードとキャレットアンダーライン |

### 出力先

呼び出し元への戻り値。通常はconsole.warnやwarn()の引数として使用。

出力例:
```
1  |  <template>
2  |    <div v-for="item in items" :key="item.id">
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3  |      {{ item.name }}
4  |    </div>
5  |  </template>
```

## 処理フロー

### 処理シーケンス

```
1. start/endをソースコード長でクランプ
   └─ Math.max(0, Math.min(value, source.length))
2. start > endの場合は空文字列を返却
3. ソースコードを改行で分割（\r?\nで分割）
   └─ 改行シーケンスと行内容を分離
4. オフセットカウンターで各行の終了位置を追跡
   └─ count >= start の行を特定
5. エラー行の前後range行（デフォルト2行）を出力
   ├─ 各行に行番号を付加（右寄せ3桁 + |）
   ├─ エラー開始行にキャレットアンダーラインを追加
   └─ 複数行エラーの場合、以降の行にもアンダーラインを追加
6. 結果行を改行で連結して返却
```

### フローチャート

```mermaid
flowchart TD
    A[generateCodeFrame呼び出し] --> B[start/endクランプ]
    B --> C{start > end?}
    C -->|Yes| D[空文字列返却]
    C -->|No| E[ソースを行分割]
    E --> F[改行シーケンスと行を分離]
    F --> G[オフセットカウントでエラー行特定]
    G --> H[エラー行 ± range行を出力]
    H --> I[行番号付加]
    I --> J{エラー行?}
    J -->|Yes| K[キャレットアンダーライン追加]
    J -->|No| L[次の行へ]
    K --> M{複数行エラー?}
    M -->|Yes| N[以降の行にもアンダーライン]
    M -->|No| O[次の行へ]
    N --> O
    L --> O
    O --> P[結果を改行連結して返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-01 | コンテキスト範囲 | エラー行の前後2行（range=2）をコンテキストとして表示する | 常時 |
| BR-68-02 | 行番号フォーマット | 行番号は右寄せで最低3桁幅、`\|`記号で区切る | 常時 |
| BR-68-03 | キャレットアンダーライン | エラー箇所は`^`記号で下線表示する。最低1文字幅 | エラー行 |
| BR-68-04 | 複数行エラー | endオフセットが複数行にまたがる場合、各行にアンダーラインを生成する | end > 行末の場合 |
| BR-68-05 | オフセットクランプ | start/endは0からsource.lengthの範囲にクランプされる | 常時 |
| BR-68-06 | 改行シーケンス対応 | `\r\n`（Windows）と`\n`（Unix）の両方の改行に対応する | 常時 |

### 計算ロジック

- アンダーラインの開始位置（pad）: `start - (count - (lineLength + newLineSeqLength))`
- アンダーラインの長さ（length）: `Math.max(1, end > count ? lineLength - pad : end - start)`

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

該当なし。

## エラー処理

エラーは発生しない。不正なstart/endはクランプ処理により安全に扱われる。

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- 開発モードでのみ使用されるため、パフォーマンス要件は厳しくない
- ソースコード分割は正規表現ベースの1回のsplit処理で完了する

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

該当なし。開発モード向けのエラー表示機能であり、本番環境では使用されない。

## 備考

- `range`定数は2に固定されており（1行目）、設定変更は不可
- `\r?\n`の改行パターンに対応するため、split後にフィルタリングで行と改行シーケンスを分離している
- 複数行にまたがるエラーの場合、`end > count`が真の間、各行にアンダーラインが追加される

---

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

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

### 推奨読解順序

#### Step 1: 関数全体の構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | codeframe.ts | `packages/shared/src/codeframe.ts` | generateCodeFrame()関数（3-64行目） |

**主要処理フロー**:
1. **1行目**: `const range: number = 2` - コンテキスト範囲の定数定義
2. **9-10行目**: start/endのクランプ処理。`Math.max(0, Math.min(value, source.length))`
3. **12行目**: `if (start > end) return ''` - 不正範囲の早期リターン
4. **18行目**: `let lines = source.split(/(\r?\n)/)` - 改行パターンでソースを分割（キャプチャグループで改行シーケンスも保持）
5. **21行目**: `newlineSequences = lines.filter((_, idx) => idx % 2 === 1)` - 偶数インデックスが行、奇数が改行
6. **22行目**: `lines = lines.filter((_, idx) => idx % 2 === 0)` - 行のみを抽出
7. **24-25行目**: `count`変数で各行末のオフセットを追跡
8. **26-29行目**: 各行の長さ+改行シーケンス長を累積
9. **30行目**: `if (count >= start)` でエラー行を特定
10. **31行目**: `for (let j = i - range; j <= i + range || end > count; j++)` でコンテキスト範囲を出力
11. **34-37行目**: 行番号フォーマット（右寄せ3桁）と行内容を出力
12. **43-50行目**: エラー開始行のアンダーライン生成（pad計算+`^`繰り返し）
13. **51-57行目**: 複数行エラーの後続行のアンダーライン生成

**読解のコツ**: `count`変数は各行を処理するたびに行の長さ+改行の長さを累積する。`count >= start`が真になった時点でエラー行が特定され、そこから前後range行分の出力が始まる。アンダーラインのpad計算は、エラー開始位置から行頭までのオフセット差分で決まる。

#### Step 2: 利用箇所を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/vue-compat/src/index.ts` | 83-91行目: コンパイルエラー時のonError関数内でgenerateCodeFrame()を呼び出し |

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

```
generateCodeFrame(source, start, end)
    │
    ├─ source.split(/(\r?\n)/)          [行分割]
    ├─ lines.filter()                   [行と改行シーケンスの分離]
    ├─ count += lineLength + newlineLen  [オフセット追跡]
    ├─ count >= start                   [エラー行特定]
    └─ res.push(...)                    [行番号+ソース+アンダーライン]
           ├─ `${line}${pad}|  ${lines[j]}`  [行番号付きソース]
           └─ `   |  ${' '.repeat(pad)}${'^'.repeat(length)}`  [アンダーライン]
```

### データフロー図

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

source (string) ────▶ generateCodeFrame()
start  (number)            │
end    (number)            ├─ 行分割
                           ├─ エラー行特定
                           ├─ コンテキスト行抽出
                           ├─ 行番号フォーマット
                           └─ アンダーライン生成 ──────▶ コードフレーム文字列

                                                          例:
                                                          "1  |  <template>
                                                           2  |    <div>
                                                              |    ^^^^^
                                                           3  |  </template>"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| codeframe.ts | `packages/shared/src/codeframe.ts` | ソース | generateCodeFrame()の定義 |
| index.ts | `packages/shared/src/index.ts` | ソース | パッケージエクスポート |
| index.ts | `packages/vue-compat/src/index.ts` | ソース | generateCodeFrame()の利用箇所（コンパイルエラー表示） |
