# 機能設計書 46-NUON

## 概要

本ドキュメントは、NushellにおけるNUON（Nushell Object Notation）形式のデータ変換機能（`from nuon`および`to nuon`コマンド）の詳細設計を記載する。NUONはNushell独自のデータシリアライズ形式であり、Nushellの全データ型をネイティブに表現できる。

### 本機能の処理概要

NUON変換機能は、Nushellのデータ構造をテキスト形式で保存・読み込みするための機能である。JSONと似た構文を持つが、日時、duration、filesize、range、binary、cell pathなどNushell固有の型をリテラルとして表現できる点が特徴である。

**業務上の目的・背景**：Nushellで扱うデータを永続化する際、JSONでは表現できない型（duration、filesize、日時等）を忠実に保存・復元する必要がある。NUONはNushell専用のフォーマットとして、すべてのデータ型を損失なく変換できる。

**機能の利用シーン**：
- Nushellスクリプトの設定ファイル保存
- データのエクスポート/インポート
- パイプライン間でのデータ受け渡し
- テストデータの作成・保存

**主要な処理内容**：
1. `from nuon`: NUON文字列をNushell Valueに変換
2. `to nuon`: Nushell ValueをNUON文字列に変換
3. `to nuon --raw`: 空白を除去したコンパクト形式
4. `to nuon --indent`: スペースでインデント
5. `to nuon --tabs`: タブでインデント
6. `to nuon --serialize`: クロージャ等を文字列化
7. `to nuon --raw-strings`: raw string構文の使用

**関連システム・外部連携**：nu-parserを使用してNUONテキストを解析。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLI専用機能のため画面なし |

## 機能種別

データ変換 / フォーマット変換

## 入力仕様

### 入力パラメータ

#### from nuon

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | String | Yes | NUON文字列（パイプライン入力） | 有効なNUON形式 |

#### to nuon

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | Any | Yes | 変換対象データ（パイプライン入力） | - |
| --raw / -r | Switch | No | 空白を全て除去 | - |
| --indent / -i | Number | No | スペースでインデント（幅指定） | 正の整数 |
| --tabs / -t | Number | No | タブでインデント（数指定） | 正の整数 |
| --serialize / -s | Switch | No | 非シリアライズ可能型を文字列化 | - |
| --raw-strings | Switch | No | raw string構文を使用 | - |

### 入力データソース

パイプライン入力（from: String型、to: Any型）

## 出力仕様

### 出力データ

#### from nuon

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | Any | パースされたNushell Value |

対応データ型:
- int, float, bool, string, binary
- list, record, table
- datetime, duration, filesize
- range, cell path, null/nothing

#### to nuon

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | String | NUON形式の文字列 |

### 出力先

標準出力（パイプライン出力）。to nuonはcontent_type: "application/x-nuon"メタデータを付与。

## 処理フロー

### 処理シーケンス

```
from nuon:
1. パイプライン入力を受け取る
   └─ String型を期待
2. EngineStateを初期化
   └─ $env.PWDを設定
3. nu_parser::parseでテキストを解析
   └─ ASTを生成
4. パイプライン構造を検証
   └─ 単一式のみ許可
5. convert_to_value関数で変換
   └─ 式の種類に応じて処理

to nuon:
1. パイプライン入力を受け取る
   └─ Any型を期待
2. スタイル設定を決定
   └─ Raw/Tabs/Spaces/Default
3. ToNuonConfigを構築
   └─ serialize_types, raw_stringsを設定
4. value_to_string関数で変換
   └─ 再帰的にNUON文字列を生成
5. メタデータを付与
   └─ content_type: application/x-nuon
```

### フローチャート

```mermaid
flowchart TD
    subgraph from_nuon ["from nuon"]
        A1[入力: String] --> B1[EngineState初期化]
        B1 --> C1[nu_parser::parse]
        C1 --> D1{パース成功?}
        D1 -->|No| E1[パースエラー]
        D1 -->|Yes| F1{単一式?}
        F1 -->|No| G1[パイプラインエラー]
        F1 -->|Yes| H1[convert_to_value]
        H1 --> I1{式タイプ判定}
        I1 -->|サポート型| J1[Value変換]
        I1 -->|非サポート| K1[エラー]
        J1 --> L1[Value出力]
    end

    subgraph to_nuon ["to nuon"]
        A2[入力: Value] --> B2{スタイル判定}
        B2 -->|--raw| C2[ToStyle::Raw]
        B2 -->|--tabs| D2[ToStyle::Tabs]
        B2 -->|--indent| E2[ToStyle::Spaces]
        B2 -->|default| F2[ToStyle::Default]
        C2 --> G2[ToNuonConfig構築]
        D2 --> G2
        E2 --> G2
        F2 --> G2
        G2 --> H2[value_to_string]
        H2 --> I2{テーブル形式?}
        I2 -->|Yes| J2[テーブル構文出力]
        I2 -->|No| K2[通常形式出力]
        J2 --> L2[String出力 + metadata]
        K2 --> L2
    end
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | NUON構文 | NushellパーサーのサブセットとしてNUONを解析 | from nuon |
| BR-46-02 | 単一式制約 | パイプラインや複数式は禁止 | from nuon |
| BR-46-03 | コード禁止 | 関数呼び出し、変数、演算子は禁止 | from nuon |
| BR-46-04 | テーブル構文 | 同一カラムのレコードリストはテーブル構文で出力 | to nuon |
| BR-46-05 | クォート省略 | クォート不要な文字列は裸で出力 | to nuon |
| BR-46-06 | クロージャ変換 | --serializeでクロージャを文字列化 | to nuon --serialize |
| BR-46-07 | raw string | --raw-stringsでr#'...'#構文を使用 | to nuon --raw-strings |
| BR-46-08 | 空白制御 | --rawで全空白を除去 | to nuon --raw |

### 計算ロジック

**サポートされるリテラル型**:
- 整数: `42`, `-10`
- 浮動小数: `3.14`, `inf`, `-inf`, `NaN`
- 真偽値: `true`, `false`
- null: `null`
- 文字列: `"hello"`, `'world'`, `r#'raw'#`
- バイナリ: `0x[ABCDEF]`
- 日時: `2000-01-01T00:00:00+00:00`
- duration: `60ns`, `1sec`, `2min`, `3hr`, `4day`, `5wk`
- filesize: `1024b`, `1kib`, `1mb`
- range: `1..10`, `0..<5`
- cell path: `$.foo.bar.0`
- リスト: `[1, 2, 3]`
- レコード: `{a: 1, b: 2}`
- テーブル: `[[col1, col2]; [a, b], [c, d]]`

**非サポートの構文**:
- 関数呼び出し（calls）
- 変数（variables）
- 演算子（operators）
- クロージャ（closures）
- ブロック（blocks）
- 文字列補間（string interpolation）
- スプレッド演算子（spread operator）

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| GenericError | パースエラー | NUON構文が不正 | NUON構文を確認 |
| OutsideSpannedLabeledError | 非サポート構文 | 変数/関数呼び出し等 | サポートされるリテラルのみ使用 |
| ColumnDefinedTwice | 重複カラム | レコード/テーブルでキー重複 | キー名を一意に |
| UnsupportedInput | 変換不可 | クロージャ等（--serializeなし） | --serializeを使用 |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

- nu_parserを使用するため、パース時にEngineStateの初期化が必要
- 大きなデータ構造では文字列連結のオーバーヘッドあり

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

- from nuonはコード実行を行わない（リテラルのみ許可）
- 任意のNushellコードの実行を防止するため、関数呼び出しや変数参照を禁止

## 備考

- NUONはNushell専用フォーマットのため、他のツールとの互換性はない
- JSONとの違い: duration、filesize、日時などのネイティブ型サポート
- content_typeは`application/x-nuon`を使用

---

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

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

### 推奨読解順序

#### Step 1: コマンドインターフェースを理解する

コマンドの定義とパラメータを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | nuon.rs (from) | `crates/nu-command/src/formats/from/nuon.rs` | FromNuon構造体（4-71行目） |
| 1-2 | nuon.rs (to) | `crates/nu-command/src/formats/to/nuon.rs` | ToNuon構造体（4-128行目） |

**読解のコツ**: to nuonの各フラグ（--raw, --indent, --tabs, --serialize, --raw-strings）がどのようにToStyleとToNuonConfigに変換されるかを理解する。

#### Step 2: from nuonのパース処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | from.rs | `crates/nuon/src/from.rs` | from_nuon関数（18-113行目） |
| 2-2 | from.rs | `crates/nuon/src/from.rs` | convert_to_value関数（115-466行目） |

**主要処理フロー**:
1. **19-23行目**: EngineState初期化と$env.PWD設定
2. **25行目**: nu_parser::parseでASTを生成
3. **27-56行目**: 複数パイプラインのエラーチェック
4. **95-108行目**: パースエラーの処理
5. **115-466行目**: 式タイプに応じたValue変換

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | to.rs | `crates/nuon/src/to.rs` | ToNuonConfig構造体（17-54行目） |
| 3-2 | to.rs | `crates/nuon/src/to.rs` | ToStyle列挙型（56-89行目） |
| 3-3 | to.rs | `crates/nuon/src/to.rs` | to_nuon関数（110-135行目） |
| 3-4 | to.rs | `crates/nuon/src/to.rs` | value_to_string関数（137-305行目） |

**主要処理フロー**:
- **117-122行目**: スタイルに応じたインデント文字列の決定
- **151-164行目**: バイナリの16進数表現
- **166-180行目**: クロージャのシリアライズ処理
- **204-267行目**: リスト/テーブルの変換
- **274-299行目**: レコードの変換
- **302行目**: 文字列のクォート処理

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

```
from nuon
    │
    ├─ FromNuon::run (49-70行目)
    │      └─ nuon::from_nuon (crates/nuon/src/from.rs:18-113行目)
    │             ├─ EngineState::default()
    │             ├─ nu_parser::parse
    │             └─ convert_to_value (再帰)
    │                    ├─ Expr::Int → Value::int
    │                    ├─ Expr::Float → Value::float
    │                    ├─ Expr::Bool → Value::bool
    │                    ├─ Expr::String → Value::string
    │                    ├─ Expr::Binary → Value::binary
    │                    ├─ Expr::DateTime → Value::date
    │                    ├─ Expr::ValueWithUnit → Value::duration/filesize
    │                    ├─ Expr::Range → Value::range
    │                    ├─ Expr::CellPath → Value::cell_path
    │                    ├─ Expr::List → Value::list (再帰)
    │                    ├─ Expr::Record → Value::record (再帰)
    │                    ├─ Expr::Table → Value::list (テーブル形式)
    │                    └─ Expr::Nothing → Value::nothing
    │
to nuon
    │
    ├─ ToNuon::run (48-88行目)
    │      ├─ ToNuonConfig構築
    │      │      └─ style, serialize_types, raw_strings設定
    │      └─ nuon::to_nuon (crates/nuon/src/to.rs:110-135行目)
    │             └─ value_to_string (再帰)
    │                    ├─ Value::Binary → 0x[...]
    │                    ├─ Value::Closure → 文字列化 (--serialize時)
    │                    ├─ Value::Bool → true/false
    │                    ├─ Value::Date → RFC3339形式
    │                    ├─ Value::Duration → {val}ns
    │                    ├─ Value::Filesize → {val}b
    │                    ├─ Value::Float → ObviousFloat
    │                    ├─ Value::Int → 数値
    │                    ├─ Value::List → [...] or [[...];...]
    │                    ├─ Value::Nothing → null
    │                    ├─ Value::Range → from..to
    │                    ├─ Value::Record → {...}
    │                    └─ Value::String → quote_string
```

### データフロー図

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

from nuon:
String ───▶ nu_parser::parse ───▶ AST ───▶ convert_to_value ───▶ Value
                 │                               │
                 └── EngineState ────────────────┘

to nuon:
Value ───▶ ToNuonConfig ───▶ value_to_string ───▶ String
                 │                  │                  │
                 ├── style ─────────┤                  └── content_type:
                 ├── serialize ─────┤                      application/x-nuon
                 └── raw_strings ───┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| nuon.rs (from) | `crates/nu-command/src/formats/from/nuon.rs` | ソース | from nuonコマンド実装 |
| nuon.rs (to) | `crates/nu-command/src/formats/to/nuon.rs` | ソース | to nuonコマンド実装 |
| lib.rs | `crates/nuon/src/lib.rs` | ソース | nuonクレートエントリーポイント |
| from.rs | `crates/nuon/src/from.rs` | ソース | NUON→Value変換ロジック |
| to.rs | `crates/nuon/src/to.rs` | ソース | Value→NUON変換ロジック |
