# 機能設計書 62-文字幅計算（getStringWidth）

## 概要

本ドキュメントは、Prettierのコードフォーマッタにおける「文字幅計算」機能の設計を記述する。この機能は、Unicode対応の文字列幅を計算し、正確な行長制御を実現する。特に東アジア文字（CJK）や絵文字などの可変幅文字を適切に処理する。

### 本機能の処理概要

**業務上の目的・背景**：コードフォーマッタが適切に行を折り返すためには、文字列の「表示幅」を正確に把握する必要がある。ASCII文字は1文字=1幅だが、日本語や中国語などの全角文字は2幅、絵文字も2幅（一部は1幅）として計算する必要がある。getStringWidth関数は、これらの複雑なUnicode文字を正確に計算し、printWidthオプションに基づく正確な行折り返しを実現する。

**機能の利用シーン**：
- フォーマット時の行長計算（printWidthとの比較）
- インデント幅の計算
- 文字列リテラルの整列
- コメント整形時の幅計算
- マルチバイト文字を含むコードの整形

**主要な処理内容**：
1. 入力文字列のASCIIのみ判定（高速パス）
2. 絵文字の検出と幅計算（emoji-regexを使用）
3. 制御文字と結合文字の除外
4. 全角・半角文字の判定（get-east-asian-widthを使用）
5. 総幅の算出

**関連システム・外部連携**：
- 外部ライブラリ: emoji-regex（絵文字検出）、get-east-asian-width（東アジア文字幅判定）、narrow-emojis（狭い絵文字判定）
- Documentプリンター: 行長計算時に使用

**権限による制御**：特になし（内部ユーティリティ関数）

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | Misc - Technical Details | 補助機能 | 文字幅計算の技術的詳細を説明 |

## 機能種別

計算処理 / ユーティリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| text | string | Yes | 幅を計算する対象文字列 | 空文字列も許容 |

### 入力データソース

- フォーマット処理中の文字列（変数名、リテラル、コメント等）
- Documentプリンターからの呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| width | number | 文字列の表示幅（整数値） |

### 出力先

- 呼び出し元への戻り値

## 処理フロー

### 処理シーケンス

```
1. 入力チェック
   └─ 空文字列の場合は0を返す
2. ASCIIのみ判定（高速パス）
   └─ /[^\x20-\x7F]/でテスト、一致なしならtext.lengthを返す
3. 絵文字処理
   └─ emoji-regexで絵文字を検出
   └─ narrow-emojisで狭い絵文字かを判定
   └─ 狭い絵文字: 1、それ以外: 2を加算し、文字列から除去
4. 残りの文字を処理
   └─ 制御文字（0x00-0x1f, 0x7f-0x9f）をスキップ
   └─ 結合文字（0x300-0x36f）をスキップ
   └─ Variation Selectors（0xfe00-0xfe0f）をスキップ
   └─ 全角/Wide文字: 2、それ以外: 1を加算
5. 総幅を返す
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{text が空?}
    B -->|Yes| C[return 0]
    B -->|No| D{ASCIIのみ?}
    D -->|Yes| E[return text.length]
    D -->|No| F[絵文字を処理して除去]
    F --> G[各文字をループ処理]
    G --> H{制御文字?}
    H -->|Yes| G
    H -->|No| I{結合文字?}
    I -->|Yes| G
    I -->|No| J{Variation Selector?}
    J -->|Yes| G
    J -->|No| K{全角/Wide?}
    K -->|Yes| L[width += 2]
    K -->|No| M[width += 1]
    L --> G
    M --> G
    G --> N[return width]
    C --> O[終了]
    E --> O
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-62-01 | ASCII高速パス | ASCII文字のみの場合は文字列長をそのまま返す | 非ASCII文字が含まれない場合 |
| BR-62-02 | 絵文字幅 | 絵文字は2幅、狭い絵文字は1幅 | 絵文字が検出された場合 |
| BR-62-03 | 全角文字幅 | isFullWidthまたはisWideの文字は2幅 | 東アジア文字の場合 |
| BR-62-04 | 制御文字除外 | 制御文字は幅0として扱う | 0x00-0x1f, 0x7f-0x9f |
| BR-62-05 | 結合文字除外 | 結合文字は幅0として扱う | 0x300-0x36f |

### 計算ロジック

```
幅 = Σ(各文字の幅)
  - ASCII文字（0x20-0x7e）: 1
  - 全角文字（isFullWidth）: 2
  - Wide文字（isWide）: 2
  - 絵文字: 2（狭い絵文字は1）
  - 制御文字: 0
  - 結合文字: 0
```

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

### 操作別データベース影響一覧

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

### テーブル別操作詳細

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本機能では例外を発生させない | - |

### リトライ仕様

該当なし

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

該当なし（データベース操作なし）

## パフォーマンス要件

- ASCII文字のみの場合は即座に結果を返す（O(1)の判定後、O(n)の文字列長取得）
- 非ASCII文字を含む場合でも線形時間（O(n)）で処理する
- 絵文字正規表現のマッチングはreplaceAllで一括処理

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

- 特別なセキュリティ要件なし
- 入力文字列に対する副作用なし

## 備考

- この関数はsindresorhus/string-widthライブラリと類似の機能を提供するが、Prettier独自の最適化が施されている
- ambiguous width文字は常にnarrow（1幅）として扱う

---

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

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

### 推奨読解順序

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

この関数は単純な入出力構造を持つ。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | get-string-width.js | `src/utilities/get-string-width.js` | 関数シグネチャと戻り値型を確認 |

**読解のコツ**: JSDocコメントで型情報が明記されている。入力はstring、出力はnumber。

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

公開APIとしてのエクスポート構造を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | public.js | `src/utilities/public.js` | getStringWidthのエクスポート |

**主要処理フロー**:
- **146行目**: `export { default as getStringWidth } from "./get-string-width.js";`

#### Step 3: 実装詳細を理解する

関数の実装ロジックを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | get-string-width.js | `src/utilities/get-string-width.js` | メイン処理ロジック |

**主要処理フロー**:
- **1-8行目**: 外部ライブラリのインポート
- **10行目**: ASCII判定用の正規表現定義
- **18-21行目**: 空文字列チェック
- **23-26行目**: ASCII高速パス
- **28-32行目**: 絵文字処理
- **37-48行目**: 制御文字・結合文字・Variation Selectorのスキップ
- **55行目**: 全角/Wide判定と幅加算

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

```
getStringWidth (get-string-width.js)
    │
    ├─ emojiRegex() [emoji-regex]
    │      └─ 絵文字パターンを生成
    │
    ├─ isNarrowEmojiCharacter() [narrow-emojis]
    │      └─ 狭い絵文字かを判定
    │
    ├─ isFullWidth() [get-east-asian-width]
    │      └─ 全角文字かを判定
    │
    └─ isWide() [get-east-asian-width]
           └─ Wide文字かを判定
```

### データフロー図

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

text ─────────────────▶ 空チェック ─────────────────────▶ 0
  │                         │
  │                    ASCIIチェック ───────────────────▶ text.length
  │                         │
  │                    絵文字処理 ──────▶ width += 1 or 2
  │                         │
  │                    文字ループ
  │                         │
  │                    制御文字判定 ──────▶ skip
  │                         │
  │                    結合文字判定 ──────▶ skip
  │                         │
  │                    全角判定 ─────────▶ width += 2
  │                         │
  │                    その他 ──────────▶ width += 1
  │                         │
  └─────────────────────────┴───────────────────────────▶ width (number)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| get-string-width.js | `src/utilities/get-string-width.js` | ソース | メイン実装 |
| public.js | `src/utilities/public.js` | ソース | 公開エクスポート |
| index.js | `src/index.js` | ソース | API公開（util経由） |
| emoji-regex | node_modules | 外部ライブラリ | 絵文字検出 |
| get-east-asian-width | node_modules | 外部ライブラリ | 東アジア文字幅判定 |
| narrow-emojis | node_modules | 外部ライブラリ | 狭い絵文字判定 |
