# 機能設計書 84-JSON処理

## 概要

本ドキュメントは、lua-language-serverにおけるJSON処理機能について記載する。この機能は、JSONデータのエンコード（Luaテーブル→JSON文字列）およびデコード（JSON文字列→Luaテーブル）を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Language Server Protocolの通信はJSON-RPCプロトコルに基づいており、すべてのメッセージはJSON形式でやり取りされる。本機能は、LuaテーブルとJSON文字列間の相互変換を提供し、LSP通信の基盤となる。また、設定ファイル（.luarc.json）の読み込みや、各種データの永続化にも使用される。純粋なLuaで実装されており、外部依存なく動作する。

**機能の利用シーン**：LSPメッセージの送受信、設定ファイルの読み込み、JSONからLuaへの変換コマンド、デバッグ出力など、JSON形式のデータを扱うすべての場面で利用される。

**主要な処理内容**：
1. Luaテーブル、文字列、数値、真偽値のJSONエンコード
2. JSON文字列のLuaテーブルへのデコード
3. Unicodeエスケープシーケンスの処理（\uXXXX）
4. サロゲートペアの処理（絵文字等の4バイト文字）
5. 空オブジェクト({})と空配列([])の区別
6. スパース配列のサポート

**関連システム・外部連携**：JSON-RPC通信（jsonrpc.lua）、JSONC処理（jsonc.lua）、設定ファイル読み込み（config/loader.lua）で使用される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 30 | JSON to Lua変換 | 主機能 | JSONをLuaテーブルに変換するコマンド処理 |

## 機能種別

データ連携 / シリアライズ・デシリアライズ

## 入力仕様

### 入力パラメータ

#### json.encode関数

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| v | any | Yes | エンコードするLua値（テーブル、文字列、数値、真偽値、nil） | json.nullまたはシリアライズ可能な型 |

#### json.decode関数

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| str | string | Yes | デコードするJSON文字列 | 文字列であること |

### 入力データソース

- LSPメッセージのJSONボディ
- 設定ファイル（.luarc.json）の内容
- ユーザーからのJSON入力

## 出力仕様

### 出力データ

#### json.encode関数

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | string | JSON形式の文字列 |

#### json.decode関数

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | any | パースされたLua値（テーブル、文字列、数値、真偽値、json.null） |

### 出力先

- JSON-RPC通信（jsonrpc.lua経由）
- 呼び出し元へのLuaテーブル返却

## 処理フロー

### 処理シーケンス

```
encode処理:
1. 値の型を判定
   └─ type(v)でnil/string/number/boolean/tableを判別
2. 型に応じた変換を実行
   └─ encode_map[type(v)](v)
3. 文字列の場合はエスケープ処理
   └─ 制御文字、\、"をエスケープ
4. 数値の場合は整数/浮動小数点を判別
   └─ math.typeで判定
5. テーブルの場合は配列/オブジェクトを判別
   └─ 最初の要素の型で判定
6. 循環参照をチェック
   └─ statusVisitedで訪問済みを管理
7. 結果を連結して返却
   └─ table.concat(statusBuilder)

decode処理:
1. 最初の非空白文字を取得
   └─ next_byte()
2. 文字に応じたパーサーを呼び出し
   └─ decode_map[byte]()
3. 文字列の場合はエスケープ解除
   └─ Unicodeエスケープ、サロゲートペア処理
4. 数値の場合は整数/浮動小数点変換
   └─ tonumber()
5. 配列/オブジェクトは再帰的にデコード
   └─ statusRefでネスト管理
6. 末尾の不正文字をチェック
   └─ trailing garbage検出
```

### フローチャート

```mermaid
flowchart TD
    subgraph encode["encode処理"]
        E1[値を受け取り] --> E2{型判定}
        E2 -->|nil| E3["'null'を返却"]
        E2 -->|string| E4[エスケープ処理]
        E4 --> E5["'\"{escaped}\"'を返却"]
        E2 -->|number| E6{整数?}
        E6 -->|Yes| E7[%dフォーマット]
        E6 -->|No| E8[%.16g/%.17gフォーマット]
        E2 -->|boolean| E9["'true'/'false'を返却"]
        E2 -->|table| E10{空テーブル?}
        E10 -->|Yes| E11{objectMt?}
        E11 -->|Yes| E12["'{}'を返却"]
        E11 -->|No| E13["'[]'を返却"]
        E10 -->|No| E14{配列?}
        E14 -->|Yes| E15[配列としてエンコード]
        E14 -->|No| E16[オブジェクトとしてエンコード]
    end

    subgraph decode["decode処理"]
        D1[JSON文字列受け取り] --> D2[next_byte]
        D2 --> D3{文字種別}
        D3 -->|"| D4[decode_string]
        D3 -->|0-9/-| D5[decode_number]
        D3 -->|t| D6[decode_true]
        D3 -->|f| D7[decode_false]
        D3 -->|n| D8[decode_null]
        D3 -->|[| D9[decode_array]
        D3 -->|{| D10[decode_object]
        D9 --> D11[再帰的にdecode]
        D10 --> D11
        D11 --> D12{statusTop > 0?}
        D12 -->|Yes| D13[decode_item]
        D13 --> D12
        D12 -->|No| D14[結果返却]
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-84-01 | 循環参照禁止 | テーブルの循環参照は検出してエラーを発生 | encode処理 |
| BR-84-02 | 混合キー禁止 | テーブルのキーは文字列か整数のどちらかに統一 | encode処理 |
| BR-84-03 | json.null | null値はjson.nullで表現（lightuserdata） | encode/decode |
| BR-84-04 | スパース配列 | supportSparseArray=trueの場合、欠けた要素はnullで埋める | encode処理 |
| BR-84-05 | 空オブジェクト判定 | objectMtメタテーブルを持つテーブルは{}としてエンコード | encode処理 |
| BR-84-06 | UTF-16オフセット | 数値フォーマットは整数と浮動小数点で分ける | encode処理 |
| BR-84-07 | Unicodeサロゲートペア | \uD800-\uDBFF + \uDC00-\uDFFFは4バイトUTF-8に変換 | decode処理 |

### 計算ロジック

サロゲートペアの変換:
```
codepoint = 0x10000 + (high - 0xD800) * 0x400 + (low - 0xDC00)
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | circular reference | テーブルに循環参照がある | 循環を解消して再試行 |
| - | invalid table: mixed or invalid key types | キー型が混在 | テーブル構造を修正 |
| - | invalid table: sparse array is not supported | スパース配列（supportSparseArray=false時） | 配列を連続にする |
| - | unexpected number value | NaN, Infinity | 有効な数値に修正 |
| - | unexpected type | function, userdata, thread | シリアライズ不可 |
| - | ERROR: xxx at line N col M | JSONパースエラー | JSON構文を修正 |
| - | expected argument of type string | decode引数が文字列でない | 文字列を渡す |

### リトライ仕様

リトライは行わない。エラー発生時は例外を発生させる。

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

本機能はトランザクションを使用しない。

## パフォーマンス要件

- エンコード・デコードは高頻度で呼び出されるため、高速に動作すること
- table.concatを使用して文字列連結を最適化
- ローカル変数にグローバル関数をキャッシュして高速化

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

- 信頼できないJSON入力に対するバリデーションは呼び出し元で行う
- 制御文字のエスケープにより安全な文字列を生成

## 備考

本実装はLua 5.1/5.2/5.3/5.4/LuaJITに対応している。Luaバージョンによりutf8.charやmath.typeの利用可否が異なるため、互換性処理が含まれている。

---

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

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

### 推奨読解順序

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

JSON処理で使用されるグローバル変数とマップを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | json.lua | `script/json.lua` | 定数とマップの定義（57-110行目） |

**読解のコツ**:
- `objectMt`: 空オブジェクト判定用のメタテーブル
- `json.null`: null値を表すlightuserdata（debug.upvalueid使用）
- `encode_escape_map`: エスケープ文字マッピング
- `decode_escape_map`: エスケープ逆変換マッピング

#### Step 2: エンコード処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | json.lua | `script/json.lua` | encode関数群（112-265行目） |

**主要処理フロー**:
1. **260-265行目**: json.encode - エントリーポイント
2. **112-115行目**: encode - 型に応じたエンコーダー呼び出し
3. **117-119行目**: encode_map["nil"] - null出力
4. **121-129行目**: encode_map.string - 文字列エスケープ
5. **146-154行目**: encode_map.number - 数値フォーマット
6. **164-247行目**: encode_map.table - 配列/オブジェクトエンコード

#### Step 3: デコード処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | json.lua | `script/json.lua` | decode関数群（270-553行目） |

**主要処理フロー**:
- **538-553行目**: json.decode - エントリーポイント
- **336-381行目**: decode_string - 文字列パース、エスケープ解除
- **383-411行目**: decode_number系 - 数値パース
- **426-448行目**: decode_true/false/null - リテラルパース
- **450-472行目**: decode_array/object - 配列/オブジェクトパース
- **510-536行目**: decode_item - ネスト要素のパース

#### Step 4: ユーティリティ関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | json.lua | `script/json.lua` | ヘルパー関数（20-56行目、63-73行目） |

**主要処理フロー**:
- **23-55行目**: utf8_char - UTF-8エンコード（Lua 5.1/5.2互換）
- **63-65行目**: createEmptyObject - 空オブジェクト作成
- **67-72行目**: isObject - テーブルがオブジェクトか判定
- **278-293行目**: find_line - エラー位置の行・列計算

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

```
json.encode(v)
    ├─ encode(v)
    │      ├─ encode_map["nil"]() → "null"
    │      ├─ encode_map.string(v)
    │      │      └─ string_gsub(v, pattern, encode_escape_map)
    │      ├─ encode_map.number(v)
    │      │      ├─ math_type(v) → "integer"/"float"
    │      │      └─ string_format / convertreal
    │      ├─ encode_map.boolean(v) → "true"/"false"
    │      └─ encode_map.table(t)
    │             ├─ 循環参照チェック (statusVisited)
    │             ├─ オブジェクトの場合: キーをソートしてエンコード
    │             └─ 配列の場合: 要素を順番にエンコード
    └─ table_concat(statusBuilder)

json.decode(str)
    ├─ next_byte()
    ├─ decode_map[byte]()
    │      ├─ decode_string()
    │      │      ├─ Unicodeエスケープ: decode_unicode_escape
    │      │      └─ サロゲートペア: decode_unicode_surrogate
    │      ├─ decode_number() / decode_number_zero() / decode_number_negative()
    │      ├─ decode_true() / decode_false() / decode_null()
    │      ├─ decode_array() → statusAry=true
    │      └─ decode_object() → statusAry=false
    ├─ decode_item() [while statusTop > 0]
    │      ├─ 配列: ref[#ref+1] = decode()
    │      └─ オブジェクト: ref[key] = decode()
    └─ trailing garbage チェック
```

### データフロー図

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

encode:
Luaテーブル ───▶ encode_map[type] ───▶ statusBuilder ───▶ JSON文字列
    │                                      │
    ├─ string → エスケープ処理 ─────────────┤
    ├─ number → フォーマット処理 ───────────┤
    ├─ boolean → "true"/"false" ───────────┤
    ├─ nil → "null" ───────────────────────┤
    └─ table → 再帰的エンコード ───────────┘

decode:
JSON文字列 ───▶ next_byte ───▶ decode_map[byte] ───▶ Luaテーブル
    │                              │
    ├─ string → エスケープ解除 ────┤
    ├─ number → tonumber ──────────┤
    ├─ true/false → boolean ───────┤
    ├─ null → json.null ───────────┤
    └─ array/object → 再帰デコード ─┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| json.lua | `script/json.lua` | ソース | JSON処理の実装 |
| jsonc.lua | `script/jsonc.lua` | ソース | コメント付きJSON処理（json.luaを拡張） |
| jsonrpc.lua | `script/jsonrpc.lua` | ソース | JSON-RPC通信（json.luaを使用） |
| jsonToLua.lua | `script/core/command/jsonToLua.lua` | ソース | JSONからLuaへの変換コマンド |
