# 预处理架构说明

## 概述

markdown2pdf 的预处理流程是**链式执行**的：

```
输入 Markdown
    │
    ▼
[1] 系统级：注入默认 frontmatter (如有)
    │
    ▼
[2] 可选：pre_remove_links() (--removelink)
    │
    ▼
[3] 内置预处理：pre_add_line_breaks()
    │
    ▼
[4] 内置预处理：pre_for_typst()
    │
    ▼
[5] 后处理：postprocess() (如有，追加执行)
    │
    ▼
[6] 可选：繁体转换 (--tc)
    │
    ▼
输出到 Pandoc → Typst → PDF
```

**关键点**：`postprocess` 是**追加执行**，内置预处理始终先执行。

---

## 一、内置预处理函数

### `pre_add_line_breaks(content, verbose=False) -> str`

**位置**：`helper_markdown/md_preprocess.py`

**功能**：添加空行分隔，使所有行变成有效段落。

**跳过块类型**：表格、引用块、代码块、frontmatter、列表、HTML块、脚注、数学公式块

---

### `pre_for_typst(content, verbose=False) -> str`

**位置**：`helper_markdown/md_preprocess.py`

**功能**：为 Typst 格式准备内容，内部调用链：
```python
content = pre_remove_titlestar(content)      # 去掉标题中的加粗标记
content = pre_dash_to_star(content)          # 下划线斜体 → 星号加粗
content = pre_for_typst_at(content)          # 转义 @
content = pre_for_typst_dollarmark(content)  # 转义 $
```

---

## 二、后处理接口

**函数签名**：
```python
postprocess: Callable[[str], str] | None
```

**调用时机**：在所有内置预处理**之后**追加执行。

**使用示例**：
```python
def my_transform(content: str) -> str:
    return content.replace("foo", "bar")

convert_file(
    input_file="article.md",
    postprocess=my_transform,
)
```

---

## 三、gaozhi 稿纸管道（已知问题）

### 当前实现

```python
# scripts/gaozhi.py
convert_file(
    template="gaozhi.typ",
    postprocess=process_for_typ,  # 作为追加后处理器
)
```

### ⚠️ 问题

`process_for_typ` 设计时假设输入是**原始 Markdown**，但实际收到的是**已经过内置预处理**的内容。

| 内置预处理操作 | 与 gaozhi 冲突 |
|--------------|---------------|
| `pre_add_line_breaks` 规范化空行 | gaozhi 有自己的换行规则 |
| `pre_for_typst` 转义 @、$ | gaozhi 输出纯文本，不需要转义 |

### 待解决

需要添加 `skip_default_preprocess` 参数或类似机制，详见 `自定义预处理方案.md`。

---

## 四、API 参考

### 预处理相关参数

| 参数 | 类型 | 说明 |
|------|------|------|
| `postprocess` | `Callable[[str], str]` | 后处理，在内置预处理后追加执行 |
| `removelink` | `bool` | 是否移除链接 |
| `tc` | `bool` | 是否转换繁体中文 |
| `default_frontmatter` | `dict` | 默认 frontmatter，在所有预处理之前注入 |

---

## 五、常见问题

### Q: 如何调试预处理结果？

A: 使用 `savemd=True` 参数，预处理后的 Markdown 将保存到临时目录。

### Q: 如何完全跳过内置预处理？

A: 目前不支持，需要添加新参数。参见 `自定义预处理方案.md`。