# 帳票設計書 7-SFC解析結果（SFCDescriptor）

## 概要

本ドキュメントは、Vue.jsのcompiler-sfcパッケージにおける`parse`関数が出力する`SFCDescriptor`の設計仕様を記述する。SFCファイルをパースし、template、script、scriptSetup、styles、customBlocksの各ブロックに分解して構造化データとして返す。

### 本帳票の処理概要

compiler-sfcの`parse`関数は、SFC（.vue）ファイルの全ソースコードを入力として受け取り、CompilerDOMのパーサーを使用してHTMLとしてパースし、各トップレベルタグ（template/script/style/カスタムブロック）を識別・分離して`SFCDescriptor`を構築する。

**業務上の目的・背景**：Vue SFCは1つのファイルにtemplate、script、styleを含む独自のファイル形式である。ビルドツールがSFCを処理するための最初のステップとして、parse関数でファイルを構造化データに分解する必要がある。分解後の各ブロックは、それぞれ専用のコンパイラ（compileTemplate、compileScript、compileStyle）に渡される。

**帳票の利用シーン**：SFCファイルの処理開始時に必ず最初に実行される。全てのSFCコンパイル処理のエントリーポイントとなる。

**主要な出力内容**：
1. `template` - テンプレートブロック（SFCTemplateBlock）
2. `script` - 通常スクリプトブロック（SFCScriptBlock）
3. `scriptSetup` - script setupブロック（SFCScriptBlock）
4. `styles` - スタイルブロック配列（SFCStyleBlock[]）
5. `customBlocks` - カスタムブロック配列（SFCBlock[]）
6. `cssVars` - CSS変数（v-bind()で参照される変数名）
7. `slotted` - :slotted()修飾子使用フラグ
8. `shouldForceReload` - HMR時のリロード判定関数
9. `filename` - ファイル名
10. `source` - 元のソースコード

**帳票の出力タイミング**：SFCファイルのビルド時に最初に実行される。

**帳票の利用者**：@vitejs/plugin-vue、vue-loader、その他のSFCビルドプラグイン、およびcompileTemplate/compileScript/compileStyle関数。

## 帳票種別

解析結果（データ構造出力）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | SFCビルドプロセス | - | SFCファイル読み込み時に自動実行 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | JavaScript/TypeScript オブジェクト（インメモリ） |
| 用紙サイズ | 該当なし |
| 向き | 該当なし |
| ファイル名 | インメモリデータ（LRUキャッシュ付き） |
| 出力方法 | 関数戻り値として返却（SFCParseResult型） |
| 文字コード | UTF-8 |

### PDF固有設定

該当なし

### Excel固有設定

該当なし

## 帳票レイアウト

### レイアウト概要

SFCParseResultは`descriptor`（SFCDescriptor）と`errors`の2フィールドを持ち、SFCDescriptorが各ブロックの構造化データを含む。

```
┌─────────────────────────────────────┐
│         SFCParseResult              │
├─────────────────────────────────────┤
│  descriptor: SFCDescriptor          │
│  ┌───────────────────────────────┐  │
│  │ filename: string              │  │
│  │ source: string                │  │
│  │ template: SFCTemplateBlock    │  │
│  │ script: SFCScriptBlock        │  │
│  │ scriptSetup: SFCScriptBlock   │  │
│  │ styles: SFCStyleBlock[]       │  │
│  │ customBlocks: SFCBlock[]      │  │
│  │ cssVars: string[]             │  │
│  │ slotted: boolean              │  │
│  │ shouldForceReload: Function   │  │
│  └───────────────────────────────┘  │
├─────────────────────────────────────┤
│  errors: (CompilerError             │
│         | SyntaxError)[]            │
└─────────────────────────────────────┘
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | filename | SFCファイル名 | options.filename / DEFAULT_FILENAME | string |
| 2 | source | SFCの全ソースコード | parse関数の引数 | string |

### 明細部

| No | 項目名 | 説明 | データ取得元 | 表示形式 | 列幅 |
|----|-------|------|-------------|---------|-----|
| 1 | template | テンプレートブロック（最大1つ） | `<template>`タグ解析 | SFCTemplateBlock / null | - |
| 2 | script | 通常スクリプトブロック（最大1つ） | `<script>`タグ解析 | SFCScriptBlock / null | - |
| 3 | scriptSetup | script setupブロック（最大1つ） | `<script setup>`タグ解析 | SFCScriptBlock / null | - |
| 4 | styles | スタイルブロック配列（複数可） | `<style>`タグ解析 | SFCStyleBlock[] | - |
| 5 | customBlocks | カスタムブロック配列 | その他のタグ解析 | SFCBlock[] | - |
| 6 | cssVars | CSS変数名配列（v-bind()で参照） | parseCssVars | string[] | - |
| 7 | slotted | :slotted()修飾子使用フラグ | スタイル内の正規表現検索 | boolean | - |

### フッター部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | shouldForceReload | HMR時のリロード判定関数 | hmrShouldReload関数 | Function |
| 2 | errors | パースエラー配列 | compiler.parse + 検証エラー | (CompilerError/SyntaxError)[] |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| source | SFCファイルの全ソースコード | Yes |
| filename | ファイル名 | No（デフォルト: 'anonymous.vue'） |
| sourceMap | ソースマップ生成フラグ | No（デフォルト: true） |
| pad | パディングモード（line/space） | No（デフォルト: false） |
| ignoreEmpty | 空ブロックの無視フラグ | No（デフォルト: true） |
| compiler | カスタムパーサー | No（デフォルト: CompilerDOM） |

### ソート順

該当なし

### 改ページ条件

該当なし

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

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

### 参照テーブル一覧

該当なし

### テーブル別参照項目詳細

該当なし

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| sourceKey | genCacheKey(source, options) | - | LRUキャッシュのキー生成 |
| cssVars | parseCssVars(descriptor) | - | style内のv-bind()からCSS変数名を抽出 |
| slotted | styles.some(s => s.scoped && slottedRE.test(s.content)) | - | scoped style内で:slotted()を使用しているか |
| templateBlock.ast | createRoot(node.children, source) | - | テンプレートのsrc属性がない場合のみ生成 |
| block.content | source.slice(loc.start.offset, loc.end.offset) | - | 各ブロックの内容をソースから切り出し |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[parse関数呼び出し] --> B{キャッシュヒット?}
    B -->|あり| C[キャッシュ結果を返却]
    B -->|なし| D[compiler.parse - SFCモードでパース]
    D --> E[ast.children走査]
    E --> F{タグ種別判定}
    F -->|template| G[descriptor.template設定]
    F -->|script| H{setup属性?}
    H -->|あり| I[descriptor.scriptSetup設定]
    H -->|なし| J[descriptor.script設定]
    F -->|style| K[descriptor.styles.push]
    F -->|その他| L[descriptor.customBlocks.push]
    G --> M[検証チェック]
    I --> M
    J --> M
    K --> M
    L --> M
    M --> N[pug/jadeテンプレートのdedent]
    N --> O[ソースマップ生成]
    O --> P[parseCssVars - CSS変数抽出]
    P --> Q[slotted判定]
    Q --> R[キャッシュに保存]
    R --> S[SFCParseResult返却]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| テンプレート重複 | `<template>`が2つ以上存在 | Single file component can contain only one `<template>` element | templateを1つにする |
| スクリプト重複 | `<script>`が2つ以上存在（同種） | Single file component can contain only one `<script>` element | scriptを1つにする |
| template functional | `<template functional>`使用 | `<template functional>` is no longer supported in Vue 3 | functional属性を除去 |
| ブロック不在 | templateもscriptもscriptSetupもない | At least one `<template>` or `<script>` is required | いずれかを追加 |
| script setup src | `<script setup>`にsrc属性 | `<script setup>` cannot use the "src" attribute | src属性を除去 |
| script src共存 | script setupと共存するscriptにsrc | `<script>` cannot use the "src" attribute when `<script setup>` is also present | src属性を除去 |
| style vars属性 | `<style vars>`使用 | `<style vars>` has been replaced by a new proposal | 新しいCSS変数構文を使用 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 1 SFCファイルにつき1回（LRUキャッシュ付き） |
| 目標出力時間 | ミリ秒オーダー |
| 同時出力数上限 | 制限なし（同期処理） |

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

parse関数は入力ソースの解析のみを行い、コード実行は行わない。ソースマップには元のSFCソースコードが含まれるため、本番環境での公開範囲に注意が必要。

## 備考

- パース結果はLRUキャッシュに保存され、同一ソースコードに対する再パースを回避する。キャッシュキーは`genCacheKey(source, options)`で生成される。
- pug/jadeテンプレートは自動的にdedent（共通インデントの除去）が行われる。
- `ignoreEmpty`オプション（デフォルト: true）により、空のブロック（templateタグ以外）は無視される。ただし`src`属性を持つブロックは空でも保持される。
- `pad`オプションにより、各ブロックの前にパディング（行番号合わせ用の空行またはスペース）を追加できる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | parse.ts | `packages/compiler-sfc/src/parse.ts` | SFCDescriptor型（72-96行目）- SFCの構造を表す中核型 |
| 1-2 | parse.ts | `packages/compiler-sfc/src/parse.ts` | SFCBlock型（35-43行目）、SFCTemplateBlock型（45-48行目）、SFCScriptBlock型（50-64行目）、SFCStyleBlock型（66-70行目） |
| 1-3 | parse.ts | `packages/compiler-sfc/src/parse.ts` | SFCParseOptions型（25-33行目）とSFCParseResult型（98-101行目） |

**読解のコツ**: SFCDescriptorはparse関数の主要出力であり、後続のcompileTemplate/compileScript/compileStyle全てがこの型のフィールドを参照する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | parse.ts | `packages/compiler-sfc/src/parse.ts` | parse関数（107-299行目）がエントリーポイント |

**主要処理フロー**:
1. **111-118行目**: LRUキャッシュチェック
2. **120-128行目**: オプションのデフォルト値設定
3. **130-141行目**: SFCDescriptor初期化
4. **144-151行目**: compiler.parseでSFCモードパース
5. **152-225行目**: ast.childrenを走査して各ブロックを分類
6. **226-252行目**: 検証チェック（必須ブロック、src属性制約）
7. **255-263行目**: pug/jadeテンプレートのdedent
8. **265-282行目**: ソースマップ生成
9. **285行目**: parseCssVarsでCSS変数抽出
10. **288-291行目**: slotted判定
11. **293-298行目**: キャッシュ保存と結果返却

#### Step 3: ブロック生成処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | parse.ts | `packages/compiler-sfc/src/parse.ts` | createBlock関数（314-351行目）- 各ブロックの生成 |
| 3-2 | parse.ts | `packages/compiler-sfc/src/parse.ts` | generateSourceMap関数（357-390行目）- ソースマップ生成 |

#### Step 4: 補助機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | parse.ts | `packages/compiler-sfc/src/parse.ts` | hmrShouldReload関数（435-457行目）- HMRリロード判定 |
| 4-2 | parse.ts | `packages/compiler-sfc/src/parse.ts` | dedent関数（465-485行目）- pug/jadeテンプレート用 |
| 4-3 | cssVars.ts | `packages/compiler-sfc/src/style/cssVars.ts` | parseCssVars関数 - CSS変数抽出 |

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

```
parse (parse.ts:107)
    |
    +-- parseCache.get(sourceKey) [キャッシュチェック]
    |
    +-- compiler.parse(source, {parseMode: 'sfc', ...})
    |       +-- CompilerDOM.parse (デフォルト)
    |
    +-- ast.children.forEach(node => ...)
    |       +-- createBlock (parse.ts:314)
    |               +-- SFCBlock / SFCTemplateBlock / SFCScriptBlock / SFCStyleBlock
    |
    +-- dedent (parse.ts:465) [pug/jade時]
    |
    +-- generateSourceMap (parse.ts:357) [sourceMap有効時]
    |       +-- new SourceMapGenerator()
    |
    +-- parseCssVars (style/cssVars.ts)
    |
    +-- parseCache.set(sourceKey, result)
    |
    +-- SFCParseResult を返却
```

### データフロー図

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

SFCソースコード          ──▶  compiler.parse           ──▶  AST (RootNode)
  (.vueファイル)                   |
                           ast.children走査
                           ┌──────────────────┐
                           │ <template> → SFCTemplateBlock │
                           │ <script>   → SFCScriptBlock   │
                           │ <script setup> → SFCScriptBlock│
                           │ <style>    → SFCStyleBlock     │
                           │ <custom>   → SFCBlock          │
                           └──────────────────┘
                                 |
SFCParseOptions                  |
  filename           ──▶  generateSourceMap     ──▶  各ブロックのmap
  sourceMap                      |
  pad                    parseCssVars           ──▶  cssVars
                                 |
                           ────────────────────────▶  SFCParseResult
                                                        { descriptor: SFCDescriptor,
                                                          errors }
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| parse.ts | `packages/compiler-sfc/src/parse.ts` | ソース | parse関数、SFCDescriptor型、SFCBlock各型定義 |
| cssVars.ts | `packages/compiler-sfc/src/style/cssVars.ts` | ソース | parseCssVars関数（CSS変数抽出） |
| cache.ts | `packages/compiler-sfc/src/cache.ts` | ソース | createCache関数（LRUキャッシュ） |
| compileScript.ts | `packages/compiler-sfc/src/compileScript.ts` | ソース | ImportBinding型（SFCScriptBlockから参照） |
| importUsageCheck.ts | `packages/compiler-sfc/src/script/importUsageCheck.ts` | ソース | isImportUsed関数（hmrShouldReloadで使用） |
| index.ts | `packages/compiler-dom/src/index.ts` | ソース | CompilerDOM（デフォルトパーサー） |
