---
description: 构建完整内容集、应用增量更新、检查结果并释放编译器资源。
---

# 编译器 API

当你自己的脚本或构建系统需要管理生命周期时，使用 `createCompiler`。Vite 和 Next 共用相同
的编译器行为，但每个创建出的实例都有自己的记录、队列和高亮器。

## 创建并关闭编译器

```ts
import { createCompiler } from '@amamo/mdx'

import amamo from './amamo.config.mjs'

const compiler = await createCompiler(amamo)
try {
  const result = await compiler.build()
  console.log(result)
} finally {
  await compiler.dispose()
}
```

创建阶段会归一化配置，并在启用高亮时初始化 Shiki。直到第一个需要原生 batch 的 `build()`
或 `transform()`，原生绑定才会被加载。

```ts
interface ICompiler {
  build(): Promise<IBuildResult>
  dispose(): Promise<void>
  remove(file: string): Promise<number>
  transform(file: string): Promise<ITransformResult>
}
```

同一编译器上的操作会串行执行。并发的 `build()` 共用一次进行中的构建，增量操作在队列中等待。

## `build()`

```ts
const result = await compiler.build()
```

一次完整构建会：

1. 按确定性顺序遍历所有集合。
2. 推导 locale、slug 和 key，并拒绝重复 key。
3. 读取全部源码和可选的最后修改时间。
4. 复用兼容的缓存记录，或执行 Rust/Shiki 编译流水线。
5. 用完整结果替换编译器的内存记录集。
6. 写入变化的 manifest 和共享生成文件，再清理过期缓存。

```ts
interface IBuildResult {
  cached: number
  compiled: number
  discovered: number
  outputsWritten: number
}
```

`outputsWritten` 统计字节发生变化的输出文件。没有变化的 warm build 可以返回 0，并保持所有
输出文件的修改时间不变；缓存记录写入不计入这个数字。

## `transform(file)`

```ts
const result = await compiler.transform('/absolute/path/content/posts/hello.mdx')
```

`transform` 编译一个属于集合的文件，替换它的记录，重写受影响的共享产物，并清理不在当前
编译器状态中的缓存记录。

```ts
interface ITransformResult {
  cached: boolean
  code: string
  map: null
  outputsWritten: number
  record: IDocumentRecord
}
```

- `code` 是编译后的 JavaScript 模块体。
- `map` 目前始终为 `null`。
- `record.frontmatter` 包含完整的、通过校验的 frontmatter 对象。
- `record.derived` 包含启用的阅读时间和最后修改时间。
- `record.hash` 是源字节的 BLAKE3 digest。
- `record.cacheKey` 还包含配置、平台、路径和可选修改时间元数据。
- `record.diagnostics` 包含成功结果的 warning，例如 `warn` 策略下的媒体缺失。

请使用绝对路径。相对路径从进程工作目录解析，不会自动从 `config.root` 解析。

> 当共享产物必须保留所有文档时，请先运行 `build()`。在全新编译器上直接调用 `transform()`，
> 会创建只包含该文件的状态。

## `remove(file)`

```ts
const outputsWritten = await compiler.remove('/absolute/path/content/posts/deleted.mdx')
```

`remove` 删除这个编译器已经知道的记录，更新共享产物，清理缓存，并返回变化的输出文件数量。
未知路径是 no-op，返回 `0`。

## `dispose()`

```ts
await compiler.dispose()
```

释放操作会清理编译器资源并销毁 Shiki。它是幂等的；之后再调用 build、transform 或 remove
会以 `AMAMO_COMPILER_DISPOSED` 拒绝。

## 错误与诊断

不同边界的失败形式不同：

- 非法 object schema 或其它配置数据会抛出 `TypeError`，消息中带 `AMAMO_CONFIG_*` code。
- 原生解析、schema、媒体、缓存和 manifest 失败会变成名为 `AmamoMdxError` 的错误，并带
  `diagnostics` 数组。
- Shiki 初始化和未知语言失败是普通 `Error`。
- 文件系统、watcher 和 Next loader 失败也是普通 `Error`。

`IDiagnostic` 从 `@amamo/mdx` 导出：

```ts
interface IDiagnostic {
  code: string
  file?: string
  hint?: string
  message: string
  range?: {
    start: { line: number; column: number; offset: number }
    end: { line: number; column: number; offset: number }
  }
  severity: 'error' | 'warning'
}
```

这个类型为 `range` 和 `hint` 预留了位置，但目前不会填充它们。batch 会在第一篇失败文档或
第一个失败阶段停止，而不会聚合全部失败。Schema 消息可能引用提交的 frontmatter 值。

## 共享生成文件

构建完成后，`generatedDirectory` 包含：

- `collections.mjs`：按顺序排列的 `{ derived, frontmatter, key, locale, slug, load }` 数组。
- `collections.d.ts`：集合注册表的配套声明产物。
- `index.json`：Next loader 使用的源码路径、缓存键、缓存目录和配置指纹。

注册表的 `load()` 会 import 原始 MDX 源码。宿主 bundler 仍需配置 Vite 插件、Next loader 或
其它兼容的 MDX transform。
