# 機能設計書 69-HTMLRewriter

## 概要

本ドキュメントは、BunランタイムのHTMLストリーム変換機能（`HTMLRewriter`）の設計仕様を記載する。

### 本機能の処理概要

`HTMLRewriter`は、HTMLドキュメントをストリーミング処理しながら変換する機能を提供する。Cloudflare Workers互換のAPIで、LOLHTML（Low-Output-Latency HTML parser）エンジンを使用した高速なHTML変換を実現する。

**業務上の目的・背景**：エッジコンピューティングやSSR（Server-Side Rendering）環境では、HTMLレスポンスの動的変換が必要となる。従来のDOMパーサーはメモリ消費が大きく遅いが、LOLHTMLを使用することでストリーミング処理による低遅延・低メモリの変換を実現する。

**機能の利用シーン**：
- HTMLレスポンスの動的書き換え
- コンテンツ注入（広告、分析タグ等）
- HTMLの最適化・minify
- A/Bテスト用コンテンツ切り替え
- セキュリティフィルタリング

**主要な処理内容**：
1. CSSセレクタによる要素選択
2. 要素・コメント・テキストの変換
3. ドキュメントレベルの変換
4. Responseオブジェクトの変換

**関連システム・外部連携**：LOLHTML（組み込み）、Fetch API（Response）

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はAPI専用であり、直接関連する画面はない |

## 機能種別

HTML処理 / ストリーム変換 / Web API

## 入力仕様

### 入力パラメータ

#### on() メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| selector | string | Yes | CSSセレクタ | LOLHTMLパース可能 |
| handlers | object | Yes | ハンドラオブジェクト | - |

##### handlers オブジェクト

| プロパティ名 | 型 | 必須 | 説明 |
|-------------|-----|-----|------|
| element | function | No | 要素ハンドラ |
| comments | function | No | コメントハンドラ |
| text | function | No | テキストハンドラ |

#### onDocument() メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| handlers | object | Yes | ドキュメントハンドラ | - |

##### handlers オブジェクト

| プロパティ名 | 型 | 必須 | 説明 |
|-------------|-----|-----|------|
| doctype | function | No | DOCTYPE ハンドラ |
| comments | function | No | コメントハンドラ |
| text | function | No | テキストハンドラ |
| end | function | No | ドキュメント終了ハンドラ |

#### transform() メソッド

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | Response/string/ArrayBuffer | Yes | 変換対象 | - |

### 入力データソース

- HTMLコンテンツ（Response、文字列、ArrayBuffer）
- CSSセレクタ
- コールバック関数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| transform結果 | Response/string/ArrayBuffer | 変換後のコンテンツ |

### 出力先

- Response オブジェクト
- 文字列
- ArrayBuffer

## 処理フロー

### 処理シーケンス

```
1. HTMLRewriter作成
   └─ LOLHTMLビルダー初期化
2. ハンドラ登録
   └─ on() / onDocument()でハンドラを追加
3. 変換実行
   └─ transform()でHTMLを処理
4. ストリーミング処理
   └─ HTMLを逐次パースしながらハンドラを実行
5. 結果返却
   └─ 変換後のコンテンツを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[HTMLRewriter作成]
    B --> C[on/onDocumentでハンドラ登録]
    C --> D[transform呼び出し]
    D --> E[入力タイプ判定]
    E -->|Response| F[Responseボディ取得]
    E -->|string/ArrayBuffer| G[一時Response作成]
    F --> H[LOLHTMLビルダー構築]
    G --> H
    H --> I[ストリーミング開始]
    I --> J{要素/コメント/テキスト検出}
    J -->|セレクタマッチ| K[ElementHandlerコールバック]
    J -->|コメント| L[CommentHandlerコールバック]
    J -->|テキスト| M[TextChunkHandlerコールバック]
    K --> N{コンテンツ変更?}
    L --> N
    M --> N
    N -->|Yes| O[変更を出力]
    N -->|No| P[元コンテンツ出力]
    O --> Q{処理完了?}
    P --> Q
    Q -->|No| J
    Q -->|Yes| R[結果返却]
    R --> S[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | セレクタ構文 | CSS標準セレクタをサポート | on()呼び出し時 |
| BR-002 | ストリーミング処理 | HTMLを逐次処理（全体をメモリに保持しない） | 常時 |
| BR-003 | 非同期ハンドラ | ハンドラはPromiseを返却可能 | 常時 |
| BR-004 | チェイン呼び出し | on/onDocumentはthisを返却 | 常時 |

### 計算ロジック

特になし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| HTMLRewriterError | パースエラー | 不正なCSSセレクタ | セレクタを修正 |
| HTMLRewriterError | 処理エラー | ハンドラ内エラー | ハンドラを確認 |
| Error | 入力エラー | 不正な入力タイプ | Response/string/ArrayBufferを使用 |
| Error | ボディ使用済み | Response bodyが既に使用 | 新しいResponseを使用 |

### リトライ仕様

特になし。

## パフォーマンス要件

- LOLHTML使用による低遅延処理
- ストリーミング処理による低メモリ使用
- 事前パース済みセレクタのキャッシュ

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

- XSS対策のためのコンテンツフィルタリングに使用可能
- ハンドラ内でのエスケープ処理は利用者責任

## 備考

- Cloudflare Workers HTMLRewriter API互換
- LOLHTMLエンジン（Rust製）を使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | HTMLRewriter構造体 |
| 1-2 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | LOLHTMLContext |

**主要処理フロー**:
- **34-53行目**: HTMLRewriter構造体定義（builder、context）
- **2-33行目**: LOLHTMLContext定義（selectors、element_handlers、document_handlers）

#### Step 2: ハンドラ登録を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | on_ |
| 2-2 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | onDocument_ |

**主要処理フロー**:
- **55-107行目**: on_関数（セレクタパース、ElementHandler登録）
- **109-157行目**: onDocument_関数（DocumentHandler登録）
- **975-1077行目**: ElementHandler構造体（onElement、onComment、onText）
- **764-888行目**: DocumentHandler構造体（onDocType、onComment、onText、onEnd）

#### Step 3: 変換処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | transform_ |
| 3-2 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | BufferOutputSink |

**主要処理フロー**:
- **175-239行目**: transform_関数（Response/string/ArrayBuffer処理）
- **395-643行目**: BufferOutputSink（出力バッファ管理）
- **169-173行目**: beginTransform（LOLHTML rewriter構築）

#### Step 4: DOM操作APIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | Element |
| 4-2 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | TextChunk |
| 4-3 | html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | Comment |

**主要処理フロー**:
- **1686-1967行目**: Element構造体（getAttribute、setAttribute、before、after等）
- **1113-1217行目**: TextChunk構造体（before、after、replace、remove）
- **1366-1486行目**: Comment構造体（before、after、replace、remove、setText）

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

```
HTMLRewriter
    │
    ├─ constructor (html_rewriter.zig)
    │      ├─ LOLHTML.HTMLRewriter.Builder.init()
    │      └─ LOLHTMLContext作成
    │
    ├─ on (html_rewriter.zig)
    │      ├─ HTMLSelector.parse
    │      ├─ ElementHandler.init
    │      └─ builder.addElementContentHandlers
    │
    ├─ onDocument (html_rewriter.zig)
    │      ├─ DocumentHandler.init
    │      └─ builder.addDocumentContentHandlers
    │
    ├─ transform (html_rewriter.zig)
    │      ├─ 入力タイプ判定
    │      ├─ BufferOutputSink.init
    │      └─ ストリーミング処理
    │
    ├─ ElementHandler
    │      ├─ onElement → Element
    │      ├─ onComment → Comment
    │      └─ onText → TextChunk
    │
    ├─ DocumentHandler
    │      ├─ onDocType → DocType
    │      ├─ onComment → Comment
    │      ├─ onText → TextChunk
    │      └─ onEnd → DocEnd
    │
    └─ DOM操作クラス
           ├─ Element（属性操作、コンテンツ変更）
           ├─ TextChunk（テキスト変更）
           ├─ Comment（コメント変更）
           ├─ DocType（DOCTYPE情報）
           ├─ DocEnd（末尾追加）
           └─ EndTag（終了タグ操作）
```

### データフロー図

```
[Response/string/ArrayBuffer]
        │
        ▼
    ┌─────────────────┐
    │ HTMLRewriter    │
    │ .transform()    │
    └────────┬────────┘
             │
             ▼
    ┌─────────────────┐
    │ LOLHTML Parser  │
    │ (ストリーミング) │
    └────────┬────────┘
             │
    ┌────────┴────────┐
    │                 │
    ▼                 ▼
┌────────┐     ┌────────────┐
│セレクタ │     │ドキュメント │
│マッチ   │     │レベル処理  │
└───┬────┘     └─────┬──────┘
    │                │
    ▼                ▼
┌────────────┐ ┌────────────────┐
│ElementHdlr│ │DocumentHandler │
│- element  │ │- doctype       │
│- comments │ │- comments      │
│- text     │ │- text          │
└─────┬─────┘ │- end           │
      │       └───────┬────────┘
      │               │
      └───────┬───────┘
              │
              ▼
    ┌─────────────────┐
    │ BufferOutputSink│
    │ (出力バッファ)  │
    └────────┬────────┘
             │
             ▼
    [変換済みResponse]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| html_rewriter.zig | `src/bun.js/api/html_rewriter.zig` | ソース | HTMLRewriter実装 |
| LOLHTML | 外部依存 | ライブラリ | HTMLパーサー・変換エンジン |
| Response.zig | `src/bun.js/webcore/Response.zig` | ソース | Response連携 |
