# 機能設計書 49-SSV

## 概要

本ドキュメントは、NushellにおけるSSV（Space-Separated Values）形式のデータ変換機能（`from ssv`コマンド）の詳細設計を記載する。SSVはスペースで区切られたテキストデータをテーブルに変換するための機能である。

### 本機能の処理概要

SSV変換機能は、スペースで区切られたテキストデータ（コマンド出力、ログファイルなど）をNushellのテーブル形式に変換する。デフォルトでは2つ以上の連続スペースを区切り文字として認識する。

**業務上の目的・背景**：UNIXコマンドの出力（ls -l、ps、df等）やログファイルは、多くの場合スペース区切りのテキストとして出力される。これらを構造化データとして扱えるようにすることで、コマンドライン処理の幅が広がる。

**機能の利用シーン**：
- UNIXコマンド出力のパース（ps、df、ls -l等）
- ログファイルの解析
- 固定幅テキストデータの処理
- カラムが整列されたテキストの変換

**主要な処理内容**：
1. `from ssv`: スペース区切りテキストをテーブルに変換
2. `from ssv --noheaders`: 1行目をヘッダーとして扱わない
3. `from ssv --aligned-columns`: カラムの整列を前提とした処理
4. `from ssv --minimum-spaces`: 区切り判定のスペース数を指定

**関連システム・外部連携**：特になし。

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| input | String | Yes | SSV文字列（パイプライン入力） | - |
| --noheaders / -n | Switch | No | 1行目をヘッダーとして扱わない | - |
| --aligned-columns / -a | Switch | No | カラムが整列されていると仮定 | - |
| --minimum-spaces / -m | Int | No | 区切り文字とする最小スペース数 | 正の整数 |

### 入力データソース

パイプライン入力（String型）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | table | パースされたテーブル |

ヘッダーあり出力構造:
```
[
  {column_name1: value, column_name2: value, ...},
  {column_name1: value, column_name2: value, ...}
]
```

ヘッダーなし出力構造:
```
[
  {column0: value, column1: value, ...},
  {column0: value, column1: value, ...}
]
```

### 出力先

標準出力（パイプライン出力）

## 処理フロー

### 処理シーケンス

```
from ssv:
1. パイプライン入力を受け取る
   └─ String型を期待
2. フラグを取得
   └─ noheaders, aligned-columns, minimum-spaces
3. 区切り文字を生成
   └─ " " * minimum_spaces (デフォルト2)
4. 空行・コメント行をフィルタ
   └─ "#"で始まる行を除外
5. ヘッダー処理を決定
   └─ noheadersで分岐
6. パース関数を選択
   └─ aligned-columnsで分岐
7. テーブルに変換して出力
   └─ IndexMapで順序保持
```

### フローチャート

```mermaid
flowchart TD
    A1[入力: String] --> B1[フラグ取得]
    B1 --> C1[区切り文字生成]
    C1 --> D1[空行・コメント行除外]
    D1 --> E1{--noheaders?}
    E1 -->|No| F1[1行目をヘッダーに]
    E1 -->|Yes| G1[column0,1...を生成]
    F1 --> H1{--aligned-columns?}
    G1 --> H1
    H1 -->|Yes| I1[parse_aligned_columns]
    H1 -->|No| J1[parse_separated_columns]
    I1 --> K1[各行をレコード変換]
    J1 --> K1
    K1 --> L1[table出力]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-49-01 | デフォルトスペース数 | 区切り文字は2スペース以上（デフォルト） | from ssv |
| BR-49-02 | コメント行フィルタ | "#"で始まる行は無視 | from ssv |
| BR-49-03 | 空行フィルタ | 空行および空白のみの行は無視 | from ssv |
| BR-49-04 | ヘッダー自動検出 | デフォルトで1行目をヘッダーとして使用 | --noheadersなし |
| BR-49-05 | 自動カラム名 | --noheaders時はcolumn0, column1...を使用 | --noheaders |
| BR-49-06 | 整列モード | --aligned-columnsでカラム位置を固定 | --aligned-columns |
| BR-49-07 | 分離モード | デフォルトで区切り文字による分割 | --aligned-columnsなし |
| BR-49-08 | トリム処理 | 各値は前後の空白をトリム | from ssv |

### 計算ロジック

**区切り文字生成**:
```
separator = " ".repeat(max(minimum_spaces, 1))
```

**parse_aligned_columns処理**:
1. ヘッダー行から各カラムの開始位置を検出
2. 各行を開始位置に基づいて分割
3. 最後のカラムは行末まで取得

**parse_separated_columns処理**:
1. 区切り文字でsplit
2. 空文字列をフィルタ
3. ヘッダーと値をzip

**noheaders時のカラム位置検出** (aligned-columns):
1. 全行からカラム開始位置を収集
2. 重複を除去してソート
3. 位置に基づいて「column{index}」を生成

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 空結果 | ヘッダー行のみの入力 | データ行を追加 |
| - | 空結果 | 空の入力 | 有効なデータを入力 |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

- 行単位のストリーム処理
- イテレータベースの遅延評価

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

- 特になし

## 備考

- UNIXコマンド出力との親和性が高い
- 最終カラムは行末まで含まれる（末尾のスペースも値に含む）
- マルチバイト文字に対応（char_indices使用）

---

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

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

### 推奨読解順序

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ssv.rs | `crates/nu-command/src/formats/from/ssv.rs` | FromSsv構造体（4-74行目） |

**読解のコツ**: デフォルトのminimum_spacesが2であること（7行目）、3つのフラグ（noheaders, aligned-columns, minimum-spaces）の役割を理解する。

#### Step 2: メイン変換処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | ssv.rs | `crates/nu-command/src/formats/from/ssv.rs` | from_ssv関数（277-300行目） |
| 2-2 | ssv.rs | `crates/nu-command/src/formats/from/ssv.rs` | string_to_table関数（227-254行目） |

**主要処理フロー**:
- **285-288行目**: フラグ取得
- **291-294行目**: minimum_spacesの決定
- **233-235行目**: 空行・コメント行のフィルタ
- **247-251行目**: パース関数の選択

#### Step 3: パース関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | ssv.rs | `crates/nu-command/src/formats/from/ssv.rs` | parse_aligned_columns関数（81-180行目） |
| 3-2 | ssv.rs | `crates/nu-command/src/formats/from/ssv.rs` | parse_separated_columns関数（182-225行目） |

**主要処理フロー**:
- **86-122行目**: construct関数（カラム位置に基づく値抽出）
- **124-142行目**: find_indices関数（カラム開始位置の検出）
- **144-156行目**: parse_with_headers（ヘッダー行からカラム定義）
- **158-174行目**: parse_without_headers（自動カラム名生成）

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

```
from ssv
    │
    ├─ FromSsv::run (65-73行目)
    │      └─ from_ssv (277-300行目)
    │             ├─ フラグ取得
    │             │      ├─ noheaders
    │             │      ├─ aligned-columns
    │             │      └─ minimum-spaces
    │             ├─ input.collect_string_strict
    │             └─ from_ssv_string_to_value (256-275行目)
    │                    └─ string_to_table (227-254行目)
    │                           ├─ lines().filter (空行・コメント除外)
    │                           ├─ HeaderOptions決定
    │                           └─ パース関数選択
    │                                  ├─ [aligned-columns]
    │                                  │      └─ parse_aligned_columns (81-180行目)
    │                                  │             ├─ find_indices
    │                                  │             ├─ parse_with_headers
    │                                  │             │      └─ construct
    │                                  │             └─ parse_without_headers
    │                                  │                    └─ construct
    │                                  └─ [default]
    │                                         └─ parse_separated_columns (182-225行目)
    │                                                ├─ parse_with_headers
    │                                                │      └─ collect
    │                                                └─ parse_without_headers
    │                                                       └─ collect
```

### データフロー図

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

String ───▶ lines() ───▶ filter ───▶ HeaderOptions ───▶ parse_* ───▶ table
                │            │               │
                │            │               ├── WithHeaders: 1行目
                │            │               └── WithoutHeaders: column{i}
                │            └── 空行/コメント除外
                └── "\n"で分割

parse_aligned_columns:
ヘッダー行 ───▶ find_indices ───▶ (カラム名, 開始位置) ───▶ construct
各データ行 ───────────────────────────────────────────────┘

parse_separated_columns:
ヘッダー行 ───▶ split(separator) ───▶ カラム名リスト ───▶ collect
各データ行 ───▶ split(separator) ───────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| ssv.rs | `crates/nu-command/src/formats/from/ssv.rs` | ソース | from ssvコマンド実装 |
