# 機能設計書 10-JSXトークン処理

## 概要

本ドキュメントは、JSX構文（<Component />等）のトークン化に対応する機能について、その処理内容、入出力仕様、およびコードリーディングガイドを記載したものである。

### 本機能の処理概要

JSXトークン処理機能は、Reactで使用されるJSX（JavaScript XML）構文をCoffeeScript内でサポートし、`<Component prop={value}>text</Component>` のような宣言的なUI記述を可能にする機能である。

**業務上の目的・背景**：ReactはモダンなWebフロントエンド開発において広く採用されており、JSX構文はReactコンポーネントの記述に必須である。CoffeeScriptでReact開発を行う場合、JSX構文のサポートが必要となる。この機能により、CoffeeScriptの簡潔な構文とJSXの宣言的なUI記述を組み合わせることができる。

**機能の利用シーン**：Reactコンポーネントの開発、CoffeeScript + React環境でのフロントエンド開発、既存CoffeeScriptプロジェクトへのReact導入時に利用される。

**主要な処理内容**：
1. `<` タグ開始の検出
2. JSX識別子（コンポーネント名）の解析
3. 属性の解析（name={value}形式）
4. 自己閉じタグ `/>` の処理
5. 子要素の解析（テキスト、補間、ネストJSX）
6. 閉じタグ `</Component>` の照合
7. フラグメント `<></>` のサポート

**関連システム・外部連携**：React、Babel（JSXトランスパイル）

**権限による制御**：特になし（すべてのユーザーが利用可能）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | Annotated Source - Lexer | 補助機能 | jsxTokenの解説を含む |
| 25 | Annotated Source - Lexer | 補助機能 | jsxTokenの解説を含む（v2） |

## 機能種別

計算処理 / テキスト解析

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| chunk | string | Yes | 現在解析中の文字列 | `<` で開始（JSXコンテキスト時） |

### 入力データソース

- Lexerのメインループから呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| consumed | number | 消費した文字数 |
| tokens | array | JSX_TAG, CALL_START, [], CALL_END等のトークン |

### 出力先

- Lexerのtokens配列に追加

## 処理フロー

### 処理シーケンス

```
1. 開始タグ検出
   └─ < + 識別子/フラグメントの検出

2. JSX_TAGトークン生成
   └─ コンポーネント名をトークン化

3. CALL_START生成
   └─ JSXをReact.createElement呼び出しとして表現

4. 属性配列開始
   └─ [ トークン生成

5. 属性解析ループ
   ├─ 属性名: IDENTIFIER
   ├─ =: ':'として処理
   └─ 属性値: 文字列または{式}

6. タグ終了判定
   ├─ /> (自己閉じ): CALL_END生成、終了
   └─ > (開始タグ終了): 子要素解析へ

7. 子要素解析
   ├─ テキスト: 文字列として処理
   ├─ {式}: 補間として処理
   └─ <子JSX>: 再帰的にJSX処理

8. 閉じタグ照合
   └─ </Component>がタグ名と一致するか確認

9. CALL_END生成
   └─ JSX全体の終了
```

### フローチャート

```mermaid
flowchart TD
    A[開始: jsxToken] --> B{< 検出?}
    B -->|No| Z[0返却]
    B -->|Yes| C{JSX識別子?}
    C -->|No| Z
    C -->|Yes| D[JSX_TAGトークン]
    D --> E[CALL_START生成]
    E --> F["[" 生成]
    F --> G{属性あり?}
    G -->|Yes| H[属性トークン]
    H --> G
    G -->|No| I{/> ?}
    I -->|Yes| J["]" CALL_END]
    I -->|No| K{> ?}
    K -->|No| Z
    K -->|Yes| L["]" 生成]
    L --> M[子要素解析]
    M --> N{</ 検出?}
    N -->|Yes| O[タグ名照合]
    N -->|No| M
    O --> P{一致?}
    P -->|Yes| Q[CALL_END生成]
    P -->|No| R[エラー: タグ不一致]
    J --> S[終了]
    Q --> S
    R --> T[エラースロー]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | タグ名一致必須 | 開始タグと閉じタグの名前が一致 | JSX終了時 |
| BR-02 | 属性スプレッド | {props...}形式の属性展開 | 属性解析時 |
| BR-03 | フラグメント | <></> 空タグサポート | フラグメント使用時 |
| BR-04 | ネストJSX | JSX内でJSXをネスト可能 | 子要素解析時 |
| BR-05 | 式補間 | {expression} で式を埋め込み | 属性値/子要素 |

### 計算ロジック

**JSX識別子正規表現**:
```coffeescript
JSX_IDENTIFIER = /^(?![\d<])(#{JSX_IDENTIFIER_PART}(?:\s*:\s*#{JSX_IDENTIFIER_PART}|(?:\s*\.\s*#{JSX_IDENTIFIER_PART})+)?)/
```

**フラグメント識別子正規表現**:
```coffeescript
JSX_FRAGMENT_IDENTIFIER = /^()>/
```

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SyntaxError | タグ不一致 | 閉じタグ名が開始タグと異なる | タグ名を修正 |
| SyntaxError | 閉じ > 欠落 | 閉じタグに > がない | > を追加 |

### リトライ仕様

リトライは行わない

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

本機能はトランザクション管理を行わない

## パフォーマンス要件

- 深くネストしたJSXでは再帰処理によりスタック消費
- 通常の使用では問題なし

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

- JSX内の式はそのまま出力される
- ユーザー入力のサニタイズはアプリケーション側の責務

## 備考

- CoffeeScript 2.x以降でサポート
- Babelの@babel/preset-reactと併用可能

---

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

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

### 推奨読解順序

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

まず、JSX関連の正規表現とフラグを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lexer.coffee | `src/lexer.coffee` | 1281-1307行目でJSX関連正規表現を確認 |
| 1-2 | lexer.coffee | `src/lexer.coffee` | 52-53行目でjsxDepth, jsxObjAttributeフラグを確認 |

**読解のコツ**: jsxDepthはJSXのネスト深度を追跡、jsxObjAttributeは属性が{...}でラップされているか追跡。

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

jsxTokenメソッドの全体構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | lexer.coffee | `src/lexer.coffee` | jsxToken（626-741行目） |

**主要処理フロー**:
1. **627-629行目**: 最初の文字と前のトークン取得
2. **630-660行目**: `<` 開始タグ処理
3. **661-674行目**: `/>` 自己閉じタグ処理
4. **675-690行目**: `{` 属性値式処理
5. **691-725行目**: `>` 開始タグ終了と子要素処理
6. **728-737行目**: `}` 属性値式終了処理

#### Step 3: 開始タグ処理を理解する

`<Component` 部分の処理を詳細に理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | lexer.coffee | `src/lexer.coffee` | 630-660行目 |

**主要処理フロー**:
- **631行目**: JSX_IDENTIFIER/JSX_FRAGMENT_IDENTIFIER マッチ
- **645-649行目**: JSX_TAGトークン生成
- **650-655行目**: プロパティ（.区切り）処理
- **656行目**: CALL_START生成
- **657行目**: [ 生成
- **658行目**: endsスタックにプッシュ
- **659行目**: jsxDepth++

#### Step 4: 自己閉じタグ処理を理解する

`/>` 処理を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | lexer.coffee | `src/lexer.coffee` | 662-674行目 |

**主要処理フロー**:
- **663行目**: '/>' ペア確認
- **664-668行目**: ] トークン生成
- **667-672行目**: CALL_END生成（自己閉じ情報付き）
- **673行目**: jsxDepth--

#### Step 5: 子要素処理を理解する

`>` 後の子要素解析を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | lexer.coffee | `src/lexer.coffee` | 691-725行目 |

**主要処理フロー**:
- **693行目**: '/>' ペアとして処理（開始タグ自体は自己閉じでない）
- **694-697行目**: ] トークン生成
- **698行目**: カンマ挿入
- **699-702行目**: matchWithInterpolationsで子要素解析
- **703-706行目**: 閉じタグ名照合
- **712-721行目**: CALL_END生成（閉じタグ情報付き）

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

```
Lexer.jsxToken (lexer.coffee:626)
    │
    ├─ [< 検出時]
    │      ├─ JSX_IDENTIFIER.exec
    │      ├─ JSX_TAGトークン生成
    │      ├─ CALL_START生成
    │      ├─ [ 生成
    │      └─ ends.push (/>待ち)
    │
    ├─ [/> 検出時]
    │      ├─ pair('/>')
    │      ├─ ] 生成
    │      └─ CALL_END生成
    │
    ├─ [{ 検出時 - 属性値式]
    │      └─ (または{ トークン生成
    │
    ├─ [> 検出時 - 開始タグ終了]
    │      ├─ ] 生成
    │      ├─ , 挿入
    │      ├─ matchWithInterpolations (子要素)
    │      │      └─ INSIDE_JSX, JSX_INTERPOLATION
    │      ├─ 閉じタグ照合
    │      └─ CALL_END生成
    │
    └─ [} 検出時 - 属性値式終了]
           ├─ pair('}')
           └─ )または} トークン生成
```

### データフロー図

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

<Button onClick={fn}>
  Click me
</Button>
       │
       ▼
  jsxToken (< 検出)
       │
       ├─ "Button"     ──▶  ['JSX_TAG', 'Button']
       │                     ['CALL_START', '(']
       │                     ['[', '[']
       │
       ├─ "onClick"    ──▶  ['IDENTIFIER', 'onClick']
       │
       ├─ "="          ──▶  [':', ':']
       │
       ├─ "{fn}"       ──▶  ['(', '(']
       │                     ['IDENTIFIER', 'fn']
       │                     [')', ')']
       │
       ├─ ">"          ──▶  [']', ']']
       │                     [',', 'JSX_COMMA']
       │
       ├─ "Click me"   ──▶  ['STRING', '"Click me"']
       │
       └─ "</Button>"  ──▶  ['CALL_END', ')']
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| lexer.coffee | `src/lexer.coffee` | ソース | jsxToken, atJSXTag, JSX関連正規表現 |
| rewriter.coffee | `src/rewriter.coffee` | ソース | JSXトークンの後処理 |
| grammar.coffee | `src/grammar.coffee` | ソース | JSX関連文法規則 |
