# 帳票設計書 5-User Data Profile Export/Import

## 概要

本ドキュメントは、VS Codeのユーザープロファイル（設定、キーバインド、拡張機能等）をJSON形式でエクスポート/インポートするUser Data Profile Export機能の帳票出力仕様を定義するものである。

### 本帳票の処理概要

User Data Profile Export/Importは、ユーザーのVS Code環境をポータブルなプロファイルとして保存・共有・復元する機能である。

**業務上の目的・背景**：開発環境の設定を複数のマシン間で共有したり、チーム内で統一された開発環境を配布したりするために使用される。また、設定のバックアップや異なるプロジェクト向けの環境切り替えにも活用される。

**帳票の利用シーン**：
- 「Profiles: Export Profile...」コマンドでプロファイルをファイルまたはGitHubリンクとしてエクスポート
- 「Profiles: Import Profile...」コマンドでプロファイルをインポート
- プロファイルメニューからのエクスポート/インポート

**主要な出力内容**：
1. プロファイル名
2. アイコン
3. 設定（settings.json）
4. キーバインド（keybindings.json）
5. タスク（tasks.json）
6. スニペット
7. UIグローバルステート
8. 拡張機能リスト

**帳票の出力タイミング**：ユーザーがエクスポートコマンドを実行し、保存先を選択した際。

**帳票の利用者**：VS Codeユーザー、開発チーム

## 帳票種別

データエクスポート / プロファイル共有

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | Profile Menu | - | Profiles: Export Profile... |
| - | Command Palette | - | Profiles: Import Profile... |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JSON |
| 用紙サイズ | N/A |
| 向き | N/A |
| ファイル名 | `{profileName}.code-profile` |
| 出力方法 | ファイルダイアログ経由 or ContentHandler経由 |
| 文字コード | UTF-8 |

### ファイル拡張子フィルター

| 項目 | 内容 |
|-----|------|
| 表示名 | PROFILE_FILTER |
| 拡張子 | .code-profile |

### 出力先オプション

| オプション | 説明 |
|-----------|------|
| Local | ローカルファイルシステムに保存 |
| GitHub Gist | GitHub Gistに保存しリンクを生成 |
| その他 | 登録されたContentHandler経由 |

## 帳票レイアウト

### レイアウト概要

IUserDataProfileTemplate interface に基づくJSONオブジェクト。

```json
{
  "name": "My Profile",
  "icon": "flame",
  "settings": "{ ... }",
  "keybindings": "[ ... ]",
  "tasks": "{ ... }",
  "snippets": "{ ... }",
  "globalState": "{ ... }",
  "extensions": "[ ... ]"
}
```

### ルートオブジェクト

| No | 項目名 | 説明 | データ型 | 必須 |
|----|-------|------|---------|------|
| 1 | name | プロファイル名 | string | Yes |
| 2 | icon | アイコン識別子 | string | No |
| 3 | settings | 設定JSON文字列 | string | No |
| 4 | keybindings | キーバインドJSON文字列 | string | No |
| 5 | tasks | タスクJSON文字列 | string | No |
| 6 | snippets | スニペットJSON文字列 | string | No |
| 7 | globalState | UIステートJSON文字列 | string | No |
| 8 | extensions | 拡張機能リストJSON文字列 | string | No |

### settingsフィールド

| No | 項目名 | 説明 | データ型 | 備考 |
|----|-------|------|---------|------|
| - | settings.json内容 | ユーザー設定全体 | string (JSON) | そのままシリアライズ |

### keybindingsフィールド

| No | 項目名 | 説明 | データ型 | 備考 |
|----|-------|------|---------|------|
| - | keybindings.json内容 | キーバインド設定 | string (JSON array) | 配列形式 |

### extensionsフィールド

| No | 項目名 | 説明 | データ型 | 備考 |
|----|-------|------|---------|------|
| 1 | identifier | 拡張機能識別子 | object | id, uuid含む |
| 2 | displayName | 表示名 | string | - |
| 3 | version | バージョン | string | - |
| 4 | preRelease | プレリリースフラグ | boolean | optional |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| プロファイル存在 | エクスポート対象のプロファイル | Yes |
| プロファイル名 | デフォルトプロファイルの場合は入力必須 | Conditional |

### エクスポートフラグ

ProfileResourceTypeFlagsによりエクスポート対象を制御：

| フラグ | デフォルト | 説明 |
|-------|----------|------|
| settings | true | 設定を含める |
| keybindings | true | キーバインドを含める |
| tasks | true | タスクを含める |
| snippets | true | スニペットを含める |
| globalState | true | UIステートを含める |
| extensions | true | 拡張機能を含める |

### 改ページ条件

N/A（JSONファイル出力のため改ページなし）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| N/A | 各リソースファイルを直接読み込み | - |

### データ取得元

#### 各リソース

| 参照項目 | 帳票項目との対応 | 取得方法 | 備考 |
|---------|----------------|---------|------|
| profile.settingsResource | settings | SettingsResource.getContent() | settings.json |
| profile.keybindingsResource | keybindings | KeybindingsResource.getContent() | keybindings.json |
| profile.tasksResource | tasks | TasksResource.getContent() | tasks.json |
| profile.snippetsHome | snippets | SnippetsResource.getContent() | snippets/* |
| profile.globalStorageHome | globalState | GlobalStateResource.getContent() | UIステート |
| profile.extensionsResource | extensions | ExtensionsResource.getContent() | 拡張機能リスト |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| プロファイル名インデックス | 既存プロファイル名からの最大値+1 | 整数 | 重複時の番号付け |

## 処理フロー

### エクスポートフロー

```mermaid
flowchart TD
    A[Export Profileコマンド] --> B[UserDataProfileExportState作成]
    B --> C[fetchRoots - リソース収集]
    C --> D{デフォルトプロファイル?}
    D -->|Yes| E[プロファイル名入力]
    D -->|No| F[既存名使用]
    E --> G[getProfileTemplate]
    F --> G
    G --> H[各リソースのgetContent]
    H --> I[IUserDataProfileTemplate構築]
    I --> J[pickProfileContentHandler]
    J --> K{出力先選択}
    K -->|Local| L[FileUserDataProfileContentHandler]
    K -->|Other| M[登録されたContentHandler]
    L --> N[showSaveDialog]
    N --> O[textFileService.create]
    M --> P[ContentHandler.saveProfile]
    O --> Q[成功ダイアログ]
    P --> Q
```

### インポートフロー

```mermaid
flowchart TD
    A[Import Profileコマンド/URL] --> B[resolveProfileContent]
    B --> C{コンテンツ取得方法}
    C -->|File| D[FileContentHandler.readProfile]
    C -->|URL| E[HTTP GET]
    C -->|Profile URL| F[ContentHandler.readProfile]
    D --> G[JSON.parse]
    E --> G
    F --> G
    G --> H{isUserDataProfileTemplate?}
    H -->|No| I[エラー: Invalid profile]
    H -->|Yes| J[getProfileToImport]
    J --> K{同名プロファイル存在?}
    K -->|Yes| L[上書き確認ダイアログ]
    K -->|No| M[新規プロファイル作成]
    L -->|Yes| N[既存プロファイル使用]
    L -->|No| O[処理終了]
    M --> P[applyProfileTemplate]
    N --> P
    P --> Q[各リソースのapply]
    Q --> R[完了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| プロファイル名空 | 必須入力が空 | "Profile name must be provided." | 名前を入力 |
| 不正なプロファイル | JSON検証失敗 | "This profile is not valid." | 正しいファイルを選択 |
| URL取得失敗 | HTTP エラー | "Failed to get profile from URL" | URL確認 |
| ファイル選択キャンセル | ダイアログでキャンセル | (処理中断) | - |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 拡張機能: 0-200件程度 |
| 目標出力時間 | 5秒以内（拡張機能インストール除く） |
| 同時出力数上限 | 1件 |

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

- プロファイルには設定値が含まれ、APIキー等の機密情報が含まれる可能性
- GitHubへのエクスポート時はGist権限が必要
- インポート時はプロファイルの妥当性検証のみで内容の安全性検証は行わない
- 共有時は機密設定の確認をユーザーに委ねる

## 備考

- .code-profile 拡張子はVS Code固有のプロファイル形式
- GitHub Gist経由でのプロファイル共有URLはvscode://スキーマを使用
- プロファイルインポート時に拡張機能のインストールが非同期で実行される

---

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

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

### 推奨読解順序

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

プロファイルテンプレートのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | IUserDataProfileTemplate interface (行44-53) |
| 1-2 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | isUserDataProfileTemplate() (行55-64) |

**読解のコツ**: IUserDataProfileTemplateがエクスポートされるJSONの構造定義。

#### Step 2: エクスポート処理を理解する

エクスポートの処理フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | exportProfile() (行222-230) |
| 2-2 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | doExportProfile() (行256-317) |
| 2-3 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | UserDataProfileExportState.getProfileTemplate() (行609-646) |

**主要処理フロー**:
- **行222-230**: exportProfile()がエントリーポイント
- **行256-317**: doExportProfile()でContentHandler選択とファイル保存
- **行609-646**: getProfileTemplate()で各リソースのgetContent()呼び出し

#### Step 3: インポート処理を理解する

インポートの処理フローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | resolveProfileTemplate() (行319-370) |
| 3-2 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | resolveProfileContent() (行406-442) |
| 3-3 | userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | applyProfileTemplate() (行180-220) |

**主要処理フロー**:
- **行319-370**: resolveProfileTemplate()でURIからテンプレート解決
- **行406-442**: resolveProfileContent()でコンテンツ取得
- **行180-220**: applyProfileTemplate()で各リソースのapply()呼び出し

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

```
Profiles: Export Profile コマンド
    │
    └─ UserDataProfileImportExportService.exportProfile()
           │
           └─ doExportProfile()
                  │
                  ├─ UserDataProfileExportState.getProfileToExport()
                  │      │
                  │      └─ quickInputService.input() (名前入力)
                  │
                  ├─ getProfileTemplate()
                  │      │
                  │      ├─ SettingsResourceTreeItem.getContent()
                  │      ├─ KeybindingsResourceTreeItem.getContent()
                  │      ├─ TasksResourceTreeItem.getContent()
                  │      ├─ SnippetsResourceTreeItem.getContent()
                  │      ├─ ExtensionsResourceTreeItem.getContent()
                  │      └─ GlobalStateResourceTreeItem.getContent()
                  │
                  ├─ pickProfileContentHandler()
                  │
                  └─ profileContentHandler.saveProfile()
                         │
                         └─ textFileService.create()
```

### データフロー図

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

IUserDataProfile     ┌─────────────────────┐
                     │                     │
  ─────────────────▶│  UserDataProfile    │
                     │  ImportExport       │
各リソースファイル   │  Service            │
 - settings.json    │                     │
 - keybindings.json │ - fetchRoots()      │──────▶ {name}.code-profile
 - tasks.json       │ - getProfileTemplate()
 - snippets/*       │ - saveProfile()     │
 - extensions       │                     │
                     └─────────────────────┘

[インポート]

{name}.code-profile  ┌─────────────────────┐
または URL           │                     │
                     │  resolveProfile     │
    ────────────────▶│  Template()         │
                     │                     │
                     │ - readProfile()     │──────▶ 新規/更新
                     │ - isUserDataProfile │        IUserDataProfile
                     │   Template()        │
                     │ - applyProfile      │
                     │   Template()        │
                     └─────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| userDataProfileImportExportService.ts | `src/vs/workbench/services/userDataProfile/browser/userDataProfileImportExportService.ts` | ソース | メイン実装 |
| userDataProfile.ts | `src/vs/workbench/services/userDataProfile/common/userDataProfile.ts` | ソース | インターフェース定義 |
| settingsResource.ts | `src/vs/workbench/services/userDataProfile/browser/settingsResource.ts` | ソース | 設定リソース |
| keybindingsResource.ts | `src/vs/workbench/services/userDataProfile/browser/keybindingsResource.ts` | ソース | キーバインドリソース |
| tasksResource.ts | `src/vs/workbench/services/userDataProfile/browser/tasksResource.ts` | ソース | タスクリソース |
| snippetsResource.ts | `src/vs/workbench/services/userDataProfile/browser/snippetsResource.ts` | ソース | スニペットリソース |
| extensionsResource.ts | `src/vs/workbench/services/userDataProfile/browser/extensionsResource.ts` | ソース | 拡張機能リソース |
| globalStateResource.ts | `src/vs/workbench/services/userDataProfile/browser/globalStateResource.ts` | ソース | UIステートリソース |
