# 機能設計書 31-jest-validate

## 概要

本ドキュメントは、jest-validateパッケージの機能設計を記載する。jest-validateは、Jest設定ファイルやCLIオプションの検証機能を提供し、ユーザーが誤った設定を行った場合に分かりやすいエラーメッセージや警告を表示する。

### 本機能の処理概要

jest-validateは、Jestの設定オプションを検証し、設定ミスを早期に検出してユーザーに通知するためのバリデーション機能を提供する。

**業務上の目的・背景**：Jestの設定ファイル（jest.config.js等）やCLIオプションには多数のオプションが存在し、ユーザーが誤った設定（タイプミス、型の不一致、非推奨オプションの使用等）を行うことがある。jest-validateは、これらの設定ミスを検出し、分かりやすいエラーメッセージと修正の提案を表示することで、ユーザーが迅速に問題を解決できるようにする。

**機能の利用シーン**：
- Jestの設定ファイル読み込み時のバリデーション
- CLI引数のパース時のバリデーション
- カスタムJest設定を提供するツールでの設定検証

**主要な処理内容**：
1. 設定オブジェクトの検証（validate関数）
2. CLIオプションの検証（validateCLIOptions関数）
3. 非推奨オプションの警告表示（deprecationWarning）
4. 未知のオプションに対する警告と類似オプションの提案（unknownOptionWarning）
5. 型不一致エラーの詳細表示（errorMessage）

**関連システム・外部連携**：
- @jest/get-type: 値の型判定に使用
- pretty-format: 値のフォーマット表示に使用
- leven: 類似オプション候補の計算（レーベンシュタイン距離）
- chalk: カラー出力

**権限による制御**：特になし（設定検証のため権限制御は不要）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | （CLI出力） | 結果表示 | バリデーションエラー・警告メッセージの表示 |

## 機能種別

バリデーション / エラー処理

## 入力仕様

### 入力パラメータ

#### validate関数

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| config | Record<string, unknown> | Yes | 検証対象の設定オブジェクト | オブジェクト型であること |
| options | ValidationOptions | Yes | 検証オプション | exampleConfigが必須 |

#### validateCLIOptions関数

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| argv | Config.Argv | Yes | yargsでパースされたCLI引数 | - |
| options | Record<string, Options> | No | 許可するCLIオプションの定義 | - |
| rawArgv | Array<string> | No | 生のCLI引数配列 | - |

#### ValidationOptions型

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| exampleConfig | Record<string, unknown> | Yes | 正しい設定の例（型チェック基準） | - |
| comment | string | No | エラーメッセージに追加するコメント | - |
| condition | function | No | カスタム検証条件関数 | - |
| deprecate | function | No | 非推奨オプション処理関数 | - |
| deprecatedConfig | DeprecatedOptions | No | 非推奨オプションの定義 | - |
| error | function | No | エラー処理関数 | - |
| recursive | boolean | No | ネストしたオブジェクトを再帰検証 | - |
| recursiveDenylist | Array<string> | No | 再帰検証から除外するパス | - |
| title | Title | No | エラー/警告タイトル | - |
| unknown | function | No | 未知オプション処理関数 | - |

### 入力データソース

- jest-config: Jest設定ファイルからの設定オブジェクト
- jest-cli: コマンドライン引数

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| hasDeprecationWarnings | boolean | 非推奨オプションの使用があったかどうか |
| isValid | boolean | 検証が成功したかどうか |

### 出力先

- コンソール出力（警告メッセージ）
- ValidationError例外（エラー時）

## 処理フロー

### 処理シーケンス

```
1. validate関数の呼び出し
   └─ 設定オブジェクトとオプションを受け取る
2. デフォルトオプションとのマージ
   └─ recursiveDenylistの結合、titleのデフォルト設定
3. 設定オブジェクトの各キーを反復処理
   └─ 各キーに対して検証を実行
4. 非推奨オプションのチェック
   └─ deprecatedConfigに含まれる場合は警告表示
5. 型の検証（condition関数）
   └─ exampleConfigの同一キーと型を比較
6. 未知オプションの検出
   └─ exampleConfigに存在しないキーの検出と警告
7. 再帰的な検証（recursive=trueの場合）
   └─ ネストしたオブジェクトの検証
8. 結果の返却
   └─ hasDeprecationWarningsとisValidを返却
```

### フローチャート

```mermaid
flowchart TD
    A[validate開始] --> B[デフォルトオプションとマージ]
    B --> C[設定の各キーをループ]
    C --> D{非推奨オプション?}
    D -->|Yes| E[deprecationWarning表示]
    D -->|No| F{exampleConfigに存在?}
    E --> F
    F -->|Yes| G{型が一致?}
    F -->|No| H{recursiveDenylistに含まれる?}
    H -->|Yes| I[スキップ]
    H -->|No| J[unknownOptionWarning表示]
    G -->|Yes| K{recursive=true?}
    G -->|No| L[ValidationError投げる]
    K -->|Yes| M[ネストオブジェクトを再帰検証]
    K -->|No| N[次のキーへ]
    I --> N
    J --> N
    M --> N
    N --> O{全キー処理完了?}
    O -->|No| C
    O -->|Yes| P[結果返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 型検証ルール | オプションの型がexampleConfigの対応する値の型と一致すること | 全設定オプション |
| BR-02 | null/undefined許可 | null/undefinedは任意の型として許可される | 全設定オプション |
| BR-03 | 関数型の特別扱い | 関数型同士は型一致とみなす | オプションが関数の場合 |
| BR-04 | maxWorkers特別処理 | maxWorkersは文字列または数値を許可 | maxWorkersオプション |
| BR-05 | コメントキー除外 | "//"キーは再帰検証から除外（NPMコメント用） | package.json検証時 |

### 計算ロジック

**類似オプション提案（leven距離）**：
- levenライブラリを使用してレーベンシュタイン距離を計算
- 距離が3未満の場合に類似オプションとして提案

```typescript
const suggestion = allowedOptions.find(option => {
  const steps: number = leven(option, unrecognized);
  return steps < 3;
});
```

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

該当なし（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ValidationError | 型不一致 | 正しい型の値を設定 |
| - | ValidationError | 未認識CLIオプション | 正しいオプション名を使用 |
| - | ValidationError | 非推奨オプション（fatal） | 新しいオプションに移行 |

### リトライ仕様

該当なし（バリデーションは即座に結果を返す）

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

該当なし

## パフォーマンス要件

- 設定ファイルのバリデーションはJest起動時に1回のみ実行
- 数百オプション規模でも即座に完了すること

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

- 設定値をログ出力する際、センシティブな情報が含まれる可能性があるため注意が必要
- pretty-formatで整形された出力は開発者向け

## 備考

- jest-validateはJest内部だけでなく、外部ツールからも利用可能な汎用バリデーションライブラリとして設計されている
- multipleValidOptions関数を使用することで、1つのオプションに複数の有効な型を指定可能

---

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

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

### 推奨読解順序

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

まず、バリデーションオプションの型定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/jest-validate/src/types.ts` | ValidationOptions型、DeprecatedOptions型の定義を理解 |

**読解のコツ**:
- `ValidationOptions`型は、検証のカスタマイズポイントを定義している
- 各プロパティ（condition, deprecate, error, unknown）はコールバック関数として検証処理をカスタマイズできる

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

外部に公開されるAPIを確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/jest-validate/src/index.ts` | エクスポートされる関数とクラスの一覧 |

**主要処理フロー**:
1. **8-13行目**: 主要なエクスポート（ValidationError, validate, validateCLIOptions等）
2. **17行目**: multipleValidOptionsのエクスポート（複数有効型の指定用）

#### Step 3: メイン検証ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | validate.ts | `packages/jest-validate/src/validate.ts` | validate関数のメインロジック |
| 3-2 | defaultConfig.ts | `packages/jest-validate/src/defaultConfig.ts` | デフォルトのバリデーション設定 |

**主要処理フロー**:
- **20-91行目**: _validate内部関数（再帰的な検証処理）
- **35-48行目**: 非推奨オプションの検出と警告
- **64-70行目**: 型検証の実行
- **97-126行目**: validate関数（エントリーポイント）
- **104-107行目**: recursiveDenylistのマージ処理

#### Step 4: 条件判定ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | condition.ts | `packages/jest-validate/src/condition.ts` | 型検証の条件判定ロジック |

**主要処理フロー**:
- **12-22行目**: validationConditionSingle（単一値の型比較）
- **35-40行目**: validationCondition（複数有効型対応）
- **42-50行目**: multipleValidOptions（複数有効型のマーカー付与）

#### Step 5: エラー・警告処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | errors.ts | `packages/jest-validate/src/errors.ts` | 型不一致エラーの生成 |
| 5-2 | warnings.ts | `packages/jest-validate/src/warnings.ts` | 未知オプション警告の生成 |
| 5-3 | deprecated.ts | `packages/jest-validate/src/deprecated.ts` | 非推奨オプション警告の生成 |
| 5-4 | utils.ts | `packages/jest-validate/src/utils.ts` | ValidationErrorクラス、ヘルパー関数 |

**主要処理フロー**:
- **utils.ts 29-41行目**: ValidationErrorクラスの実装
- **utils.ts 52-62行目**: createDidYouMeanMessage（類似オプション提案）
- **errors.ts 14-38行目**: errorMessage関数（型エラー詳細生成）

#### Step 6: CLIオプション検証を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | validateCLIOptions.ts | `packages/jest-validate/src/validateCLIOptions.ts` | CLI専用の検証ロジック |

**主要処理フロー**:
- **76-125行目**: validateCLIOptions関数のメインロジック
- **85-89行目**: 許可オプションのSet構築
- **113-118行目**: 未認識オプションの検出
- **29-56行目**: createCLIValidationError（エラーメッセージ生成）

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

```
validate (validate.ts)
    │
    ├─ defaultConfig (defaultConfig.ts)
    │      ├─ validationCondition (condition.ts)
    │      ├─ deprecationWarning (deprecated.ts)
    │      ├─ errorMessage (errors.ts)
    │      └─ unknownOptionWarning (warnings.ts)
    │
    └─ _validate (validate.ts) [再帰呼び出し]
           ├─ options.deprecate → deprecationWarning
           ├─ options.condition → validationCondition
           ├─ options.error → errorMessage
           └─ options.unknown → unknownOptionWarning

validateCLIOptions (validateCLIOptions.ts)
    │
    ├─ validateDeprecatedOptions
    │      └─ logValidationWarning (utils.ts)
    │
    └─ createCLIValidationError
           └─ createDidYouMeanMessage (utils.ts)
```

### データフロー図

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

設定オブジェクト ───────▶ validate() ───────────────────▶ { hasDeprecationWarnings, isValid }
     │                        │
     │                        ├─ 非推奨チェック ──────────▶ 警告メッセージ (console.warn)
     │                        │
     │                        ├─ 型チェック ──────────────▶ ValidationError (throw)
     │                        │
     │                        └─ 未知オプションチェック ──▶ 警告メッセージ (console.warn)
     │
exampleConfig ─────────▶ 型比較の基準として使用


CLI引数 ────────────────▶ validateCLIOptions() ─────────▶ true (成功)
     │                        │
     │                        ├─ 非推奨チェック ──────────▶ 警告/ValidationError
     │                        │
     │                        └─ 未認識オプションチェック ▶ ValidationError (throw)
     │
CLIオプション定義 ──────▶ 許可オプションリストとして使用
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/jest-validate/src/index.ts` | ソース | パブリックAPIのエクスポート |
| types.ts | `packages/jest-validate/src/types.ts` | ソース | 型定義 |
| validate.ts | `packages/jest-validate/src/validate.ts` | ソース | メインの検証ロジック |
| validateCLIOptions.ts | `packages/jest-validate/src/validateCLIOptions.ts` | ソース | CLI検証ロジック |
| condition.ts | `packages/jest-validate/src/condition.ts` | ソース | 条件判定ロジック |
| defaultConfig.ts | `packages/jest-validate/src/defaultConfig.ts` | ソース | デフォルト設定 |
| errors.ts | `packages/jest-validate/src/errors.ts` | ソース | エラーメッセージ生成 |
| warnings.ts | `packages/jest-validate/src/warnings.ts` | ソース | 警告メッセージ生成 |
| deprecated.ts | `packages/jest-validate/src/deprecated.ts` | ソース | 非推奨警告処理 |
| utils.ts | `packages/jest-validate/src/utils.ts` | ソース | ユーティリティ関数 |
| package.json | `packages/jest-validate/package.json` | 設定 | パッケージ定義 |
