# 機能設計書 90-静的解析

## 概要

本ドキュメントは、Next.jsにおけるページ・ルートセグメントファイルの静的解析（Static Analysis）に関する機能設計書である。SWCパーサーによるAST解析を通じて、ページのエクスポート情報・セグメント設定・RSCモジュール情報を抽出し、ビルドパイプラインに必要な静的情報を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Next.jsのビルドプロセスでは、各ページ・ルートセグメントファイルの特性（SSG/SSR判定、ランタイム指定、動的パラメータ対応等）をビルド時に把握する必要がある。静的解析は、実際にモジュールを実行することなくSWCのAST解析によりこれらの情報を高速に抽出する。これにより、ビルドプランの最適化、適切なバンドリング、ランタイム割り当てが可能となる。

**機能の利用シーン**：`next build`時にすべてのページ・ルートセグメントファイルに対して実行される。App Router（`app/`ディレクトリ）とPages Router（`pages/`ディレクトリ）の両方のファイルを対象とする。また、Middleware（`middleware.ts`）およびProxy（`proxy.ts`）ファイルの解析にも使用される。`next dev`時にもHMR更新時に再解析が行われる。

**主要な処理内容**：
1. SWCパーサーによるソースコードのAST（抽象構文木）変換（LRUキャッシュ付き）
2. エクスポート関数の検出（`getStaticProps`、`getServerSideProps`、`generateStaticParams`、`generateImageMetadata`、`generateSitemaps`）
3. ディレクティブの検出（`'use client'`、`'use server'`）
4. エクスポートされた定数値の抽出（`export const runtime`、`export const revalidate`等）
5. RSCモジュール情報の抽出（`__next_internal_client_entry_do_not_use__`、`__next_internal_action_entry_do_not_use__`コメントマーカー解析）
6. Zodスキーマによるセグメント設定のバリデーション（App/Pages/Middleware別）
7. Middleware/Proxyマッチャーの解析とパス正規表現への変換

**関連システム・外部連携**：SWCパーサー（`@next/swc`）、Zodバリデーション、Webpackビルドパイプライン、Turbopackビルドパイプライン

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能は画面を持たないビルド時静的解析処理である |

## 機能種別

静的解析 / ビルド処理 / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pageFilePath | string | Yes | 解析対象ファイルの絶対パス | 有効なファイルパス |
| nextConfig | Partial<NextConfig> | Yes | Next.js設定オブジェクト | - |
| isDev | boolean | Yes | 開発モードかどうか | - |
| page | string | Yes | ページのルートパス（例: `/about`） | - |
| pageType | PAGE_TYPES | Yes | APP または PAGES | PAGE_TYPES.APP / PAGE_TYPES.PAGES |

### 入力データソース

- JavaScript/TypeScriptソースファイル（`app/`および`pages/`ディレクトリ配下）
- `next.config.js`設定オブジェクト（`basePath`、`i18n`設定等）
- ファイルシステム（ソースファイルの読み取り）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| type | PAGE_TYPES | APP または PAGES |
| ssg | boolean (App) | SSG対象かどうか |
| ssr | boolean (App) | SSR対象かどうか |
| rsc | RSCModuleType | 'server' または 'client' |
| getStaticProps | boolean (Pages) | getStaticPropsエクスポートの有無 |
| getServerSideProps | boolean (Pages) | getServerSidePropsエクスポートの有無 |
| generateStaticParams | boolean | generateStaticParamsエクスポートの有無 |
| generateImageMetadata | boolean | generateImageMetadataエクスポートの有無 |
| generateSitemaps | boolean | generateSitemapsエクスポートの有無 |
| config | AppSegmentConfig / PagesSegmentConfig | セグメント設定（revalidate、dynamic、fetchCache等） |
| runtime | string | ランタイム指定（'edge'、'nodejs'等） |
| preferredRegion | string / string[] | 優先リージョン設定 |
| maxDuration | number | 最大実行時間（秒） |
| middleware | ProxyConfig | Middleware/Proxyマッチャー設定 |
| hadUnsupportedValue | boolean | 未サポート値の検出有無 |

### 出力先

- ビルドパイプライン（Webpack/Turbopack）の内部データ構造
- ビルド計画（SSG/SSR判定、ランタイム割り当て）

## 処理フロー

### 処理シーケンス

```
1. getPageStaticInfo呼び出し
   └─ pageTypeに基づきgetAppPageStaticInfo / getPagesPageStaticInfoに分岐
2. ファイル読み込み
   └─ tryToReadFile: ファイルの内容を読み取り
   └─ PARSE_PATTERNによる事前フィルタ（解析不要なファイルをスキップ）
3. SWC AST解析
   └─ parseModule: SHA1ハッシュによるLRUキャッシュ（500エントリ）付きSWCパース
4. Middleware/Proxy検証
   └─ validateMiddlewareProxyExports: エクスポート形式の検証
5. エクスポート検出
   └─ checkExports: 関数・変数エクスポートの検出
   └─ ディレクティブ（'use client'/'use server'）の検出
6. RSCモジュール情報の抽出
   └─ getRSCModuleInformation: クライアント/サーバーモジュール判定
7. 定数値の抽出
   └─ extractExportedConstValue: AST走査によるリテラル値の抽出
8. セグメント設定のバリデーション
   └─ parseAppSegmentConfig / parsePagesSegmentConfig: Zodスキーマバリデーション
9. Middleware設定の解析
   └─ parseMiddlewareConfig: マッチャーパターンの正規表現変換
10. 結果の構築と返却
    └─ PageStaticInfo（AppPageStaticInfo / PagesPageStaticInfo）の返却
```

### フローチャート

```mermaid
flowchart TD
    A[getPageStaticInfo呼び出し] --> B{pageType}
    B -->|APP| C[getAppPageStaticInfo]
    B -->|PAGES| D[getPagesPageStaticInfo]
    C --> E[ファイル読み込み]
    D --> E
    E --> F{PARSE_PATTERN一致?}
    F -->|No| G[空のPageStaticInfo返却]
    F -->|Yes| H[parseModule - SWC AST解析]
    H --> I[validateMiddlewareProxyExports]
    I --> J[checkExports - エクスポート検出]
    J --> K[getRSCModuleInformation]
    K --> L[extractExportedConstValue - 定数値抽出]
    L --> M[parseSegmentConfig - Zodバリデーション]
    M --> N{Edge Runtime + generateStaticParams?}
    N -->|Yes| O[エラー: 排他制約違反]
    N -->|No| P{use client + generateStaticParams?}
    P -->|Yes| Q[エラー: 排他制約違反]
    P -->|No| R[PageStaticInfo構築・返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-90-01 | 事前フィルタ | PARSE_PATTERNに一致しないファイルは解析をスキップし、空の結果を返す | 全ファイル |
| BR-90-02 | パーサー選択 | SWCパーサーで`isModule: 'unknown'`として解析（モジュール種別自動判定） | 全ファイル |
| BR-90-03 | Edge+generateStaticParams排他 | `export const runtime = 'edge'`と`generateStaticParams`の同時エクスポートはエラー | App Router |
| BR-90-04 | useClient+generateStaticParams排他 | `'use client'`ディレクティブと`generateStaticParams`の同時使用はエラー | App Router |
| BR-90-05 | Proxyランタイム制限 | Proxyファイルでのランタイム指定は無効（常にNode.js） | proxy.ts |
| BR-90-06 | experimental-edge警告 | `runtime: 'experimental-edge'`使用時は`'edge'`への移行を警告 | Pages Router |
| BR-90-07 | 再エクスポート警告 | 設定値がリテラルではなく再エクスポートの場合、デフォルト値使用を警告 | 全ファイル |
| BR-90-08 | LRUキャッシュ | AST解析結果をSHA1ハッシュベースの500エントリLRUキャッシュに保持 | 全ファイル |
| BR-90-09 | unstable_prefetch制限 | `unstable_prefetch`は`cacheComponents`有効時のみ使用可能 | App Router |

### 計算ロジック

**PARSE_PATTERN（事前フィルタ正規表現）**：
```
/(?<!(_jsx|jsx-))runtime|preferredRegion|getStaticProps|getServerSideProps|generateStaticParams|export const|generateImageMetadata|generateSitemaps|middleware|proxy/
```
- 否定後読み`(?<!(_jsx|jsx-))`により、`jsx-runtime`や`_jsx_runtime`への誤マッチを回避

**RSCモジュール判定**：
- `__next_internal_client_entry_do_not_use__`コメントマーカーの存在で`client`モジュールと判定
- `__next_internal_action_entry_do_not_use__`コメントマーカーでServer Actionメタデータを抽出

**定数値抽出（extractValue）**：
- サポート型: `null`, `boolean`, `string`, `number`, `RegExp`, `undefined`, `Array`, `Object`, `TemplateLiteral`（式なし）, `TsSatisfiesExpression`
- スプレッド演算子、テンプレートリテラル内の式、未知のIdentifierは`UnsupportedValueError`

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | Edge Runtime + generateStaticParams同時使用 | いずれかを削除 |
| - | Error | 'use client' + generateStaticParams同時使用 | generateStaticParamsをサーバーコンポーネントに移動 |
| - | Error | unstable_prefetch使用時にcacheComponents無効 | cacheComponentsを有効化 |
| - | Error | Zodバリデーション失敗（不正なセグメント設定） | ドキュメントに従い設定を修正 |
| - | Error | Middleware/Proxyファイルに有効なエクスポートなし | default exportまたはnamed exportを追加 |
| - | Warning | UnsupportedValueError（動的な値のエクスポート） | リテラル値に変更 |
| - | Warning | experimental-edgeランタイムの使用 | 'edge'に変更 |
| - | Error | Middlewareソースパスの不正（Zod検証失敗） | パスパターンを修正 |

### リトライ仕様

リトライは行わない。ファイル読み込み失敗時、開発モードでは`undefined`を返し、プロダクションビルドではエラーをスローする。

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

トランザクション管理は不要。

## パフォーマンス要件

- SWCパーサーによる高速なAST解析（Babel比で大幅に高速）
- LRUキャッシュ（500エントリ）によるAST解析結果の再利用（SHA1ハッシュベース）
- PARSE_PATTERNによる事前フィルタで不要なファイルの解析をスキップ
- LRUキャッシュ（250エントリ）によるAPI Route警告の重複抑制
- LRUキャッシュ（250エントリ）によるUnsupportedValue警告の重複抑制

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

- 静的解析はファイル内容を読み取るのみで、コード実行は行わない
- Middlewareマッチャーのソースパスは正規表現として解析されるため、不正なパターンはZodバリデーションで拒否される

## 備考

- App Router（`app/`ディレクトリ）のセグメント設定: `revalidate`, `dynamicParams`, `dynamic`, `fetchCache`, `unstable_prefetch`, `preferredRegion`, `runtime`, `maxDuration`
- Pages Router（`pages/`ディレクトリ）のセグメント設定: `runtime`, `maxDuration`, `config`（ネストされたオブジェクト）
- `extractExportedConstValue`は`export const`宣言のみを対象とし、`let`/`var`は無視する
- RSCモジュール情報はSWC変換後のバンドル済みソースコードに付与されたコメントマーカーから抽出される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **48-111行目**: `ProxyMatcher`, `ProxyConfig`, `AppPageStaticInfo`, `PagesPageStaticInfo`, `PageStaticInfo`型定義 |
| 1-2 | app-segment-config.ts | `packages/next/src/build/segment-config/app/app-segment-config.ts` | **92-146行目**: `AppSegmentConfigSchema`（Zod）と**196-243行目**: `AppSegmentConfig`型 |
| 1-3 | pages-segment-config.ts | `packages/next/src/build/segment-config/pages/pages-segment-config.ts` | **7-34行目**: `PagesSegmentConfigSchema`と**82-97行目**: `PagesSegmentConfig`型 |
| 1-4 | middleware-config.ts | `packages/next/src/build/segment-config/middleware/middleware-config.ts` | **95-111行目**: `MiddlewareConfigInputSchema`（matcher, regions, unstable_allowDynamic） |

**読解のコツ**: 静的解析の出力型（`PageStaticInfo`）がビルドパイプライン全体で使用される。App RouterとPages Routerで異なるインターフェースを持つ判別共用体（discriminated union）であることに注意。セグメント設定のバリデーションはZodスキーマで行われる。

#### Step 2: AST解析基盤を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | parse-module.ts | `packages/next/src/build/analysis/parse-module.ts` | **1-15行目**: `parseModule`関数 - LRUキャッシュ（500エントリ）+ SHA1ハッシュベースのSWCパーサーラッパー |
| 2-2 | extract-const-value.ts | `packages/next/src/build/analysis/extract-const-value.ts` | **19行目**: `NoSuchDeclarationError`、**73-101行目**: `UnsupportedValueError`（パス情報付き） |
| 2-3 | extract-const-value.ts | `packages/next/src/build/analysis/extract-const-value.ts` | **103-210行目**: `extractValue`関数 - ASTノード型ごとのリテラル値抽出 |
| 2-4 | extract-const-value.ts | `packages/next/src/build/analysis/extract-const-value.ts` | **226-256行目**: `extractExportedConstValue`関数 - `export const`宣言の走査とextractValue呼び出し |

**主要処理フロー**:
1. **10-14行目（parse-module.ts）**: `withPromiseCache`でLRUキャッシュを使い、SHA1ハッシュをキーにSWC `parse`を呼び出し
2. **230-253行目（extract-const-value.ts）**: モジュールボディを走査し、`ExportDeclaration` -> `VariableDeclaration` -> `kind === 'const'`の条件で対象を特定
3. **103-210行目（extract-const-value.ts）**: ノード型に応じた値抽出（BooleanLiteral, StringLiteral, NumericLiteral, ArrayExpression, ObjectExpression等）

#### Step 3: エクスポート検出とRSCモジュール情報を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **113-124行目**: RSCモジュールラベル定義（CLIENT_MODULE_LABEL, ACTION_MODULE_LABEL, ディレクティブ定数） |
| 3-2 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **125-160行目**: `getRSCModuleInformation`関数 - コメントマーカーによるクライアント/サーバー判定 |
| 3-3 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **169-306行目**: `checkExports`関数 - AST走査によるエクスポート関数・変数・ディレクティブの検出 |

**主要処理フロー**:
- **129-134行目**: ACTION_MODULE_LABELとCLIENT_MODULE_LABELの正規表現マッチ
- **137-143行目**: 非React Serverレイヤーの場合はclientとして返却
- **149-159行目**: React Serverレイヤーでのクライアント参照情報の抽出
- **203-291行目**: AST bodyの各ノードを走査し、`ExportDeclaration`（関数・変数）および`ExportNamedDeclaration`（re-export）を検出
- **206-217行目**: ファイル先頭のディレクティブ（`'use client'`/`'use server'`）を検出

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **827-835行目**: `getPageStaticInfo`関数 - pageTypeによるApp/Pages分岐 |
| 4-2 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **612-706行目**: `getAppPageStaticInfo`関数 - App Routerページの解析 |
| 4-3 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **708-818行目**: `getPagesPageStaticInfo`関数 - Pages Routerページの解析 |

**主要処理フロー**:
1. **618-628行目**: ファイル読み込みとPARSE_PATTERNによる事前フィルタ
2. **630行目**: `parseModule`によるSWC AST解析
3. **631-636行目**: `validateMiddlewareProxyExports`によるMiddleware/Proxyエクスポート検証
4. **638-644行目**: `checkExports`によるエクスポート情報の抽出
5. **646行目**: `getRSCModuleInformation`によるRSCモジュール判定
6. **648-668行目**: `extractExportedConstValue`によるセグメント設定値の抽出
7. **671行目**: `parseAppSegmentConfig`によるZodバリデーション
8. **674-691行目**: 排他制約のチェック（Edge+generateStaticParams、useClient+generateStaticParams、unstable_prefetch+cacheComponents）

#### Step 5: Middleware設定解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **446-500行目**: `getMiddlewareMatchers`関数 - マッチャーパターンの正規表現変換 |
| 5-2 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **502-539行目**: `parseMiddlewareConfig`関数 - Middlewareコンフィグのバリデーションと変換 |
| 5-3 | get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | **308-428行目**: `validateMiddlewareProxyExports`関数 - Middleware/Proxyファイルのエクスポート検証 |

**主要処理フロー**:
- **456-476行目**: マッチャーソースパスにi18nロケールパターンとnextDataパターンを追加
- **477-479行目**: basePathプレフィックスの追加
- **482-490行目**: SourceSchemaによるバリデーション（失敗時はprocess.exit(1)）
- **496行目**: `tryToParsePath`による正規表現への変換

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

```
next build / next dev
    |
    +-- getPageStaticInfo(params)              # メインエントリーポイント
            |
            +-- getAppPageStaticInfo()         # App Router解析
            |   |
            |   +-- tryToReadFile()            # ファイル読み込み
            |   +-- PARSE_PATTERN.test()       # 事前フィルタ
            |   +-- parseModule()              # SWC AST解析
            |   |       +-- parse() [SWC]      # SWCパーサー呼び出し
            |   |       +-- LRUCache(500)      # SHA1ハッシュベースキャッシュ
            |   |
            |   +-- validateMiddlewareProxyExports()  # Middleware/Proxy検証
            |   +-- checkExports()             # エクスポート検出
            |   +-- getRSCModuleInformation()  # RSCモジュール判定
            |   +-- extractExportedConstValue() # 定数値抽出
            |   |       +-- extractValue()     # ASTノード値抽出（再帰）
            |   |
            |   +-- parseAppSegmentConfig()    # Zodバリデーション
            |   +-- parseMiddlewareConfig()    # Middleware設定解析
            |           +-- getMiddlewareMatchers()  # マッチャー正規表現変換
            |                   +-- tryToParsePath() # パス正規表現生成
            |
            +-- getPagesPageStaticInfo()       # Pages Router解析
                |
                +-- tryToReadFile()
                +-- parseModule()
                +-- validateMiddlewareProxyExports()
                +-- checkExports()
                +-- getRSCModuleInformation()
                +-- extractExportedConstValue()
                +-- parsePagesSegmentConfig()   # Zodバリデーション
                +-- parseMiddlewareConfig()
```

### データフロー図

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

ソースファイル ────────────▶ tryToReadFile() ─────┐
                                                  │
                             PARSE_PATTERN ◄──────┤ 事前フィルタ
                                                  │
                             parseModule() ◄──────┤ SWC AST解析
                                  |               │
                                  v               │
next.config.js ──────────▶ checkExports() ────────┤
                           getRSCModuleInformation()│
                           extractExportedConstValue()│
                                  |               │
                                  v               ├──▶ PageStaticInfo
                           parseAppSegmentConfig() │      (type, rsc,
                           parsePagesSegmentConfig()│       runtime,
                                  |               │       config,
                                  v               │       middleware,
                           parseMiddlewareConfig() │       ...)
                           getMiddlewareMatchers() │
                                                  │
SWCコメントマーカー ──────▶ RSCモジュール判定 ─────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| get-page-static-info.ts | `packages/next/src/build/analysis/get-page-static-info.ts` | ソース | メイン静的解析モジュール（getPageStaticInfo, checkExports, getRSCModuleInformation等） |
| extract-const-value.ts | `packages/next/src/build/analysis/extract-const-value.ts` | ソース | AST定数値抽出（extractExportedConstValue, extractValue） |
| parse-module.ts | `packages/next/src/build/analysis/parse-module.ts` | ソース | SWCパーサーラッパー（LRUキャッシュ付き） |
| app-segment-config.ts | `packages/next/src/build/segment-config/app/app-segment-config.ts` | ソース | App Routerセグメント設定Zodスキーマ・パーサー |
| pages-segment-config.ts | `packages/next/src/build/segment-config/pages/pages-segment-config.ts` | ソース | Pages Routerセグメント設定Zodスキーマ・パーサー |
| middleware-config.ts | `packages/next/src/build/segment-config/middleware/middleware-config.ts` | ソース | Middleware設定Zodスキーマ（マッチャー、リージョン等） |
| try-to-parse-path.ts | `packages/next/src/lib/try-to-parse-path.ts` | ソース | パスパターンの正規表現変換 |
| constants.ts | `packages/next/src/lib/constants.ts` | ソース | MIDDLEWARE_FILENAME, PROXY_FILENAME等の定数 |
| page-types.ts | `packages/next/src/lib/page-types.ts` | ソース | PAGE_TYPES列挙（APP, PAGES） |
| lru-cache.ts | `packages/next/src/server/lib/lru-cache.ts` | ソース | LRUキャッシュ実装 |
| with-promise-cache.ts | `packages/next/src/lib/with-promise-cache.ts` | ソース | Promiseキャッシュラッパー |
