# 機能設計書 35-astオプション

## 概要

本ドキュメントは、CoffeeScript CLIの`--ast`オプションの機能設計を記述する。このオプションは、CoffeeScriptソースコードをBabel互換のAbstract Syntax Tree（AST）に変換し、JSON形式で出力する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：CoffeeScriptコードの静的解析、リンター、コード変換ツール、IDE/エディタ拡張機能など、ASTを必要とするツールとの連携を可能にする。Babel互換形式により、既存のJavaScriptエコシステムとの相互運用性を確保する。開発者がコードの構造を可視化してデバッグや学習に活用できるようにする。

**機能の利用シーン**：
- CoffeeScriptコードの静的解析ツールを開発したい場合
- カスタムリンターやコード品質チェックツールを作成したい場合
- コードの構造をJSON形式で取得して別のツールで処理したい場合
- CoffeeScriptコンパイラの動作を理解・デバッグしたい場合
- IDE拡張機能でシンタックスハイライトや補完機能を実装したい場合

**主要な処理内容**：
1. `--ast`オプションが指定されているかを判定
2. コンパイルオプションにast: trueを設定
3. ソースコードをトークン化・パース
4. パース結果のノードツリーからBabel互換ASTを生成
5. ASTの位置情報を修正（ルートノードの調整）
6. JSON形式に変換して標準出力に出力

**関連システム・外部連携**：Babelエコシステム、ESLint、各種静的解析ツールとの連携を想定。

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

## 関連画面

本機能はCLI機能のため、画面との直接的な関連はない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | - |

## 機能種別

コード解析 / AST生成

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --ast | Boolean | No | AST出力モードを有効にする | - |
| source | String | Yes | CoffeeScriptソースコード | 構文的に正しいCoffeeScriptであること |

### 入力データソース

- ソースファイル
- 標準入力（`--stdio`との併用時）
- コマンドライン引数（`--eval`との併用時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| AST | Object (JSON) | Babel互換のAST。File/Programノードを含む |

### AST構造

```json
{
  "type": "File",
  "start": 0,
  "end": <code_length>,
  "range": [0, <code_length>],
  "loc": {
    "start": {"line": 1, "column": 0},
    "end": {"line": <last_line>, "column": <last_column>}
  },
  "program": {
    "type": "Program",
    "body": [...],
    "directives": [],
    "start": 0,
    "end": <code_length>,
    "range": [0, <code_length>],
    "loc": {...}
  },
  "tokens": [...]
}
```

### 出力先

標準出力（JSON形式、インデント付き）

## 処理フロー

### 処理シーケンス

```
1. オプション解析
   └─ opts.astがtrueに設定される
2. compileOptions関数でのast設定
   └─ options.ast = true
3. compileScript関数での分岐
   └─ opts.astがtrueの場合、専用の処理パスへ
4. CoffeeScript.compile呼び出し
   └─ options.ast = trueでcompile関数を呼び出し
5. compile関数内でのAST生成
   └─ トークン化、パース後、nodes.ast(options)を呼び出し
6. 位置情報の修正
   └─ ルートノード（File/Program）の位置情報を調整
7. トークン配列の付加
   └─ ast.tokens = tokens
8. JSON出力
   └─ JSON.stringify(compiled, null, 2)でフォーマット
```

### フローチャート

```mermaid
flowchart TD
    A[coffee --ast file.coffee] --> B[parseOptions]
    B --> C[opts.ast = true]
    C --> D[compileScript file, input, base]
    D --> E[compileOptions で options.ast = true]
    E --> F{opts.ast?}
    F -->|Yes| G[CoffeeScript.compile input, options]
    G --> H[lexer.tokenize code, options]
    H --> I[parser.parse tokens]
    I --> J{options.ast?}
    J -->|Yes| K[nodes.allCommentTokens = helpers.extractAllCommentTokens]
    K --> L[nodes.ast options]
    L --> M[位置情報修正]
    M --> N[ast.tokens = tokens]
    N --> O[return ast]
    O --> P[JSON.stringify compiled, null, 2]
    P --> Q[printLine 出力]
    J -->|No| R[通常コンパイル処理]
    F -->|No| R
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-35-01 | Babel互換形式 | 生成されるASTはBabelのAST形式と互換性を持つ | 常時 |
| BR-35-02 | 位置情報完全性 | すべてのノードにstart、end、range、loc情報を含む | 常時 |
| BR-35-03 | トークン付加 | ASTにはソーストークン配列が付加される | 常時 |
| BR-35-04 | コメント保持 | コメントトークンはallCommentTokensとして抽出・保持される | 常時 |
| BR-35-05 | ルート位置修正 | File/Programノードの位置情報はソースコード全体を正確に反映 | 常時 |

### 計算ロジック

**位置情報の修正ロジック（coffeescript.coffee内）**:
```coffeescript
range = [0, code.length]
ast.start = ast.program.start = range[0]
ast.end = ast.program.end = range[1]
ast.range = ast.program.range = range
ast.loc.start = ast.program.loc.start = {line: 1, column: 0}
ast.loc.end.line = ast.program.loc.end.line = sourceCodeNumberOfLines
ast.loc.end.column = ast.program.loc.end.column = sourceCodeLastLine.length
```

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SYNTAX_ERROR | SyntaxError | ソースコードに構文エラーがある | コードの構文を修正する |
| - | 論理エラー | AST生成中のノード変換エラー | バグとして報告する |

### リトライ仕様

リトライは行わない。

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

該当なし。

## パフォーマンス要件

- AST生成は通常のコンパイルよりも高速（JavaScript生成を省略）
- 出力JSONのサイズは元ソースの数倍になる場合がある

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

- AST出力はソースコードの構造を完全に露出するため、機密コードの取り扱いに注意

## 備考

**AST出力例**:

入力:
```coffeescript
add = (a, b) -> a + b
```

出力（抜粋）:
```json
{
  "type": "File",
  "program": {
    "type": "Program",
    "body": [
      {
        "type": "ExpressionStatement",
        "expression": {
          "type": "AssignmentExpression",
          "operator": "=",
          "left": {
            "type": "Identifier",
            "name": "add"
          },
          "right": {
            "type": "ArrowFunctionExpression",
            "params": [
              {"type": "Identifier", "name": "a"},
              {"type": "Identifier", "name": "b"}
            ],
            "body": {
              "type": "BinaryExpression",
              "operator": "+",
              "left": {"type": "Identifier", "name": "a"},
              "right": {"type": "Identifier", "name": "b"}
            }
          }
        }
      }
    ]
  }
}
```

---

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

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

### 推奨読解順序

#### Step 1: オプション定義を理解する

まず、--astオプションがどのように定義されているかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | command.coffee | `src/command.coffee` | SWITCHESでの--astオプション定義 |

**主要処理フロー**:
- **35行目**: `--ast`オプションの定義（`'generate an abstract syntax tree of nodes'`）
- 短縮形なし（`--ast`のみ）

#### Step 2: compileScript内でのAST処理分岐を理解する

コンパイル処理でASTモードがどのように分岐するかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.coffee | `src/command.coffee` | compileScript関数内のasts分岐 |

**主要処理フロー**:
- **211-213行目**: AST処理の分岐
  ```coffeescript
  else if opts.ast
    compiled = CoffeeScript.compile task.input, task.options
    printLine JSON.stringify(compiled, null, 2)
  ```

**読解のコツ**: `opts.ast`がtrueの場合、compile関数の戻り値がASTオブジェクトになり、それをJSON.stringifyでフォーマットして出力している。

#### Step 3: compileOptions内でのastフラグ設定を理解する

コンパイルオプションにastフラグがどのように設定されるかを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | command.coffee | `src/command.coffee` | compileOptions関数 |

**主要処理フロー**:
- **509行目**: `ast: opts.ast` - オプションオブジェクトにastフラグを設定

#### Step 4: compile関数内でのAST生成処理を理解する

核心部分であるAST生成の実装を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | coffeescript.coffee | `src/coffeescript.coffee` | compile関数内のAST生成処理 |

**主要処理フロー**:
- **62-107行目**: compile関数内のAST関連処理
- **88行目**: `nodes = parser.parse tokens` - パースしてノードツリーを生成
- **94-107行目**: AST生成の分岐
  ```coffeescript
  if options.ast
    nodes.allCommentTokens = helpers.extractAllCommentTokens tokens
    sourceCodeNumberOfLines = (code.match(/\r?\n/g) or '').length + 1
    sourceCodeLastLine = /.*$/.exec(code)[0]
    ast = nodes.ast options
    range = [0, code.length]
    ast.start = ast.program.start = range[0]
    ast.end = ast.program.end = range[1]
    ast.range = ast.program.range = range
    ast.loc.start = ast.program.loc.start = {line: 1, column: 0}
    ast.loc.end.line = ast.program.loc.end.line = sourceCodeNumberOfLines
    ast.loc.end.column = ast.program.loc.end.column = sourceCodeLastLine.length
    ast.tokens = tokens
    return ast
  ```

**読解のコツ**:
- `nodes.ast(options)`はnodesモジュールの各ノードクラスに実装されたastメソッドを呼び出してBabel互換ASTを生成
- 位置情報の修正はlexerの`clean`関数で先頭のコメント等が除去された影響を補正するため

#### Step 5: helpers.extractAllCommentTokensを理解する

コメントトークンの抽出処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | helpers.coffee | `src/helpers.coffee` | extractAllCommentTokens関数 |

**主要処理フロー**:
- **112-120行目**: extractAllCommentTokens関数
  ```coffeescript
  exports.extractAllCommentTokens = (tokens) ->
    allCommentsObj = {}
    for token in tokens when token.comments
      for comment in token.comments
        commentKey = comment.locationData.range[0]
        allCommentsObj[commentKey] = comment
    sortedKeys = Object.keys(allCommentsObj).sort (a, b) -> a - b
    for key in sortedKeys
      allCommentsObj[key]
  ```

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

```
exports.run (command.coffee:72)
    │
    ├─ parseOptions (command.coffee:445)
    │      └─ opts.ast = true
    │
    └─ compileScript (command.coffee:202)
           │
           ├─ compileOptions(file, base) (command.coffee:452)
           │      └─ ast: opts.ast
           │
           └─ opts.ast チェック (command.coffee:211)
                  │
                  └─ CoffeeScript.compile(input, options)
                         │
                         ├─ lexer.tokenize(code, options)
                         │
                         ├─ parser.parse(tokens)
                         │      └─ nodes (構文木)
                         │
                         ├─ options.ast チェック
                         │
                         ├─ helpers.extractAllCommentTokens(tokens)
                         │
                         ├─ nodes.ast(options)
                         │      └─ Babel互換AST生成
                         │
                         ├─ 位置情報修正
                         │
                         └─ return ast
                  │
                  └─ JSON.stringify(ast, null, 2)
                         │
                         └─ printLine(json)
```

### データフロー図

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

CoffeeScript              Tokenize                          Tokens
ソースコード    ───▶      lexer.tokenize        ───▶      [token, token, ...]
                                │
                                ▼
                          Parse
                          parser.parse            ───▶      Nodes (構文木)
                                │
                                ▼
                          AST生成
                          nodes.ast(options)      ───▶      Babel互換AST
                                │
                                ▼
                          位置情報修正
                          range, loc調整          ───▶      修正済みAST
                                │
                                ▼
                          JSON変換
                          JSON.stringify          ───▶      JSON文字列
                                │
                                ▼
                          出力
                          printLine               ───▶      標準出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| command.coffee | `src/command.coffee` | ソース | CLI本体、compileScript内AST処理分岐 |
| coffeescript.coffee | `src/coffeescript.coffee` | ソース | compile関数、AST生成・位置修正処理 |
| helpers.coffee | `src/helpers.coffee` | ソース | extractAllCommentTokens関数 |
| nodes.coffee | `src/nodes.coffee` | ソース | 各ノードクラスのastメソッド（Babel互換AST生成） |
| lexer.coffee | `src/lexer.coffee` | ソース | tokenize関数（トークン生成） |
| parser.js | `lib/coffeescript/parser.js` | 生成物 | Jisonパーサー（ノードツリー生成） |
