---
description: 集合、MDX、数学公式、高亮、媒体、派生字段、manifest、缓存和生成产物的准确默认值与行为。
---

# 配置

`defineConfig` 会原样返回参数。`normalizeConfig` 才是运行时边界：它把集合的 Zod schema 转成
JSON Schema、拒绝其它非纯数据、应用默认值、解析路径，并返回所有编译器和适配器共用的
`IAmamoMDXConfig`。

```ts
import { defineConfig, z } from '@amamo/mdx'

export default defineConfig({
  collections: {
    posts: {
      directory: 'content/posts',
      schema: z.object({}),
    },
  },
})
```

至少需要一个集合。

## 顶层配置

| 键                   | 默认值          | 作用                                             |
| -------------------- | --------------- | ------------------------------------------------ |
| `root`               | `process.cwd()` | 相对配置路径的基准目录。                         |
| `collections`        | 必填            | 内容目录、schema、locale 和 slug。               |
| `mdx`                | 见下文          | MDX 语法、数学公式和 JSX runtime 选项。          |
| `highlight`          | 启用 Shiki      | 语法高亮策略；设为 `false` 可禁用。              |
| `media`              | 启用重写        | Markdown 媒体 import 策略；设为 `false` 可禁用。 |
| `derived`            | 全部关闭        | 阅读时间和最后修改时间。                         |
| `manifests`          | `{}`            | 命名 JSON 投影。                                 |
| `cache`              | 启用            | 持久化编译记录；设为 `false` 可禁用。            |
| `generatedDirectory` | `.amamo-mdx`    | 注册表、声明文件和 Next 私有索引目录。           |

除集合的 Zod schema 外，函数、symbol、访问器、类实例、循环引用、`undefined`、`bigint` 和
非有限数字都会被拒绝。检查发生在配置模块本身已经 import 之后，因此不会沙箱化那个模块。

## 集合

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

collections: {
  posts: {
    directory: 'content/posts',
    extensions: ['.mdx'],
    locales: { default: 'en', names: ['en', 'zh-CN'] },
    schema: z.object({
      title: z.string(),
      draft: z.boolean().default(false),
    }),
    slug: { indexNames: ['index', 'page'] },
  },
}
```

| 键                | 默认值              | 行为                                            |
| ----------------- | ------------------- | ----------------------------------------------- |
| `directory`       | 必填                | 从 `root` 解析；调用 `build()` 前目录必须存在。 |
| `extensions`      | `['.mdx']`          | 纳入集合的后缀；每项必须以 `.` 开头。           |
| `locales`         | 无                  | 可选的基于文件名的 locale 映射。                |
| `schema`          | 必填                | 校验 YAML frontmatter 的 Zod object schema。    |
| `slug.indexNames` | `['index', 'page']` | 推导 slug 时省略的 basename。                   |

包内维护 Zod，并对外提供兼容的 `z` builder。配置边界是结构化的 `IFrontmatterSchema` 接口，
因此也可以传入其它兼容的 object schema。Object schema 会转换为 JSON Schema Draft 2020-12；
原始 JSON Schema 对象会被拒绝。Rust 会在校验前应用 `.default()` 值，但不会执行 Zod parse、
类型转换、transform 或自定义 refinement。请只使用可表示为 JSON Schema 的类型和内置检查。
诊断可能包含用户提交的值；不要把原始构建错误暴露给不可信用户。

配置 locale 后，无后缀文件使用默认 locale；`page.zh-CN.mdx` 这样的已知后缀会选择对应 locale。
默认 locale 必须出现在 `names` 中。文档身份推导如下：

```text
posts/guide.mdx          -> slug "guide", key "en:guide", locale "en"
posts/guide.zh-CN.mdx    -> slug "guide", key "zh-CN:guide", locale "zh-CN"
posts/index.mdx          -> slug "/",     key "en:/",     locale "en"
```

没有 locale 配置时，key 就是 slug。完整构建会拒绝同一集合内的重复 key。

> Next 适配器目前只注册 `*.mdx`。直接编译器和 Vite 插件可以处理自定义集合后缀，但内置
> Next loader 不可以。

## MDX

```ts
mdx: {
  extensions: {
    footnotes: true,
    headingIds: false,
    taskLists: true,
  },
  gfm: true,
  hardBreaks: false,
  jsxImportSource: 'react',
  math: false,
  providerImportSource: '',
}
```

| 键                     | 默认值    | 行为                                                  |
| ---------------------- | --------- | ----------------------------------------------------- |
| `extensions`           | 见下文    | 可选 Markdown 语法。                                  |
| `gfm`                  | `true`    | 启用整套 GFM；脚注与任务列表可以单独覆盖。            |
| `hardBreaks`           | `false`   | 把文本节点内的换行转换成 `<br>`。                     |
| `jsxImportSource`      | `'react'` | 编译模块使用的 JSX runtime 包。                       |
| `math`                 | 关闭      | 构建期数学解析与渲染；设为 `{}` 启用。                |
| `providerImportSource` | `''`      | 可选的 MDX 组件 provider import；空字符串表示不导入。 |

手写的 ESM 和 MDX JSX 仍会进入编译模块。`providerImportSource` 控制 MDX 组件 provider 的
接线，不是保留或删除 JSX 的开关。

### Markdown 扩展

每项受支持的扩展都可以独立启用：

| 键           | 默认值   | 行为                           |
| ------------ | -------- | ------------------------------ |
| `footnotes`  | 继承 GFM | `引用[^id]` 与 `[^id]: 定义`。 |
| `headingIds` | `false`  | 根据静态标题文字生成 ID。      |
| `taskLists`  | 继承 GFM | `- [ ] 待办` 与 `- [x] 完成`。 |

显式设置 `footnotes` 或 `taskLists` 时以显式值为准，否则它们跟随 `gfm`。因此可以在关闭其余
GFM 语法时单独启用它们，也可以在保留表格、自动链接等 GFM 语法时单独关闭。

生成的脚注锚点会按文档增加命名空间，因此同一页面渲染多篇编译文档时不会产生重复 ID。自动
标题 ID 会把文字转成小写、保留 Unicode 字母与数字、把其余连续字符替换为连字符，并为重复
标题追加 `-2`、`-3`。需要手动固定 ID 时，可以直接写
`<h2 id="custom-id">标题</h2>`。

这里不额外定义高亮、上下标或定义列表的缩写语法；无需配置即可直接使用标准 MDX 元素
`<mark>`、`<sub>`、`<sup>` 与 `<dl>`。

## 数学公式

```ts
mdx: {
  math: {
    singleDollar: true,
    macros: {
      '\\RR': '\\mathbb{R}',
    },
  },
},
```

数学语法需要显式启用。`mdx.math: {}` 会渲染行内 `$x$` 与块级 `$$` 公式；`mdx.math: false`
会把美元符号继续当成普通文字。`singleDollar: false` 可关闭 `$x$` 行内形式，适合货币内容较多的站点。
使用默认值时，文字中的美元符号应写成 `\$`。

`macros` 把单个 TeX 控制序列映射到固定展开值。每个展开值不超过 1 KiB，命令名与展开值合计
不超过 16 KiB。参数占位符以及 `\\def`、`\\newcommand` 等动态定义命令会被拒绝。配置会复制到每个
公式的独立解析器中，因此定义不会在公式或文档之间泄漏。

RaTeX 在 Rust 编译器内完成解析、排版与渲染。编译模块只包含自包含 SVG 输出，不需要浏览器
数学运行时、样式表、webfont、原始 HTML 或 `dangerouslySetInnerHTML`。非法 TeX 产生
`AMAMO_MATH_PARSE`；不安全、外部引用或无法嵌入字形的 SVG 产生 `AMAMO_MATH_RENDER`，不会
静默回退到外部字体。KaTeX 字体未覆盖的 Unicode 字形可能使用构建机上的系统字体，因此不同
构建机生成的轮廓可能不同。只有当构建机的回退字体许可嵌入与再分发时，才应发布这些字形。

每个表达式最多包含 64 KiB TeX、100,000 个展开 token、8 MiB 或 100,000 个节点的解析 AST、
合计 100,000 个展开后的 array 单元格、10,000 个排版项、任一方向 10,000 em、16 MiB SVG 与
100,000 个 SVG 节点。语法与结构限制失败会产生 `AMAMO_MATH_PARSE`；排版或 SVG 限制失败会产生
`AMAMO_MATH_RENDER`。

行内 SVG 使用 RaTeX 的 depth 对齐基线，并通过 `currentColor` 继承文字颜色；显式 TeX 颜色仍会
保留。外层元素提供 `role="math"`，并把原始表达式作为无障碍标签。RaTeX 当前不生成 MathML，
因此公式文本不可选择，辅助技术接收到的是 TeX 标签而不是 MathML 树。

## 语法高亮

```ts
highlight: {
  provider: 'shiki',
  engine: 'oniguruma',
  languages: 'auto',
  themes: { light: 'vitesse-light', dark: 'vitesse-dark' },
  unknownLanguage: 'error',
  colorReplacements: {},
}
```

| 键                  | 默认值           | 行为                                        |
| ------------------- | ---------------- | ------------------------------------------- |
| `provider`          | `'shiki'`        | 固定字面量；目前不提供其它 provider。       |
| `engine`            | `'oniguruma'`    | Shiki 的 `oniguruma` 或 `javascript` 引擎。 |
| `languages`         | `'auto'`         | 按需加载，或预加载列出的内置语言。          |
| `themes`            | Vitesse 明暗主题 | Shiki 内置主题名。                          |
| `unknownLanguage`   | `'error'`        | 拒绝未知语言，或按 `'plain'` 渲染。         |
| `colorReplacements` | `{}`             | Shiki 的颜色替换映射。                      |

显式语言数组只是预加载这些语法，不会阻止之后按需加载其它语言。Shiki 在内存中复用语言加载；
高亮结果保存在文档缓存记录内，不存在单独的磁盘高亮缓存。

设置 `highlight: false` 可跳过代码块高亮。

## 媒体

```ts
media: {
  attributes: {
    audio: ['src'],
    embed: ['src'],
    img: ['src', 'srcset'],
    object: ['data'],
    source: ['src', 'srcset'],
    track: ['src'],
    video: ['src', 'poster'],
  },
  missing: 'error',
}
```

上表是默认属性映射。只要提供 `attributes`，就会替换整张默认表；请把仍需重写的标签全部列出。

由 Markdown 元素产生的相对 URL 会从源文件解析并变成静态 import。绝对路径、fragment、
协议相对 URL、data URL 和带 scheme 的 URL 会原样通过。手写的 MDX JSX（例如
`<img src="./manual.png" />`）不会被重写。

| `missing` | 结果                                                                 |
| --------- | -------------------------------------------------------------------- |
| `'error'` | 拒绝这次全新编译。                                                   |
| `'warn'`  | 保留原始 URL，并向 `record.diagnostics` 添加 `AMAMO_MEDIA_MISSING`。 |

直接编译器和 Vite 适配器不会自动打印 warning。设置 `media: false` 可禁用重写。

## 派生字段

```ts
derived: {
  lastModified: false,
  readingTime: false,
}
```

`readingTime` 排除代码，把每个连续 ASCII 单词或每个中日韩字符计为一个单位。分钟数为
`ceil(units / 300)`，并且最少一分钟。

`lastModified` 优先使用文件最近一次 Git commit 的时间，取不到时回退到文件系统修改时间。启用
的值会出现在 `record.derived` 中，也会成为编译模块的具名导出。

## Manifest

```ts
manifests: {
  public: {
    output: '.amamo-mdx/public.json',
    collections: ['posts'],
    sort: [{ field: 'publishedAt', direction: 'desc' }],
    fields: {
      key: 'key',
      title: 'title',
      publishedAt: { from: 'publishedAt', default: null },
    },
  },
  server: {
    output: '.amamo-mdx/server.json',
    key: 'key',
    fields: {
      key: 'key',
      tokenPresent: { from: 'accessToken', transform: 'exists' },
      tokenFingerprint: { from: 'accessToken', transform: 'sha256' },
    },
  },
}
```

| 键            | 默认值   | 行为                                                       |
| ------------- | -------- | ---------------------------------------------------------- |
| `output`      | 必填     | 从 `root` 解析的 JSON 路径，与 `generatedDirectory` 无关。 |
| `collections` | 全部集合 | 纳入这个 manifest 的集合名。                               |
| `fields`      | 必填     | 输出字段到源投影的映射。                                   |
| `sort`        | `[]`     | 有序的投影字段排序键；direction 默认 `asc`。               |
| `key`         | 无       | 不设置时输出数组；设置后输出以这个投影字段为键的对象。     |

配置 `key` 后，对应名称必须存在于投影记录中，并解析成唯一的 string、number 或 boolean。
缺失、null、object、array 和重复值都会让构建失败。缺失或 null 的排序值在升降序中都保持最后，
最终用文档 key 打破平局。

投影路径可以读取顶层 frontmatter，或以下保留值：

- `collection`、`file`、`key`、`locale` 和 `slug`
- `frontmatter.<path>`
- `derived.<path>`

字段值可以是路径字符串，也可以是 `{ from, transform?, default? }`。

| Transform    | 结果                                                                     |
| ------------ | ------------------------------------------------------------------------ |
| 无           | 复制源值；不存在时使用 `default`，再不存在则为 `null`。                  |
| `'exists'`   | 源值存在且非 null 时为 `true`。                                          |
| `'sha256'`   | 字符串或 JSON 序列化值的小写 SHA-256 hex；缺失时使用 `default` 或 null。 |
| `'mediaUrl'` | 绝对或外部 URL 原样通过；相对字符串映射为 root-relative URL。            |

`mediaUrl` 只是路径投影，不会检查文件存在性，也不会创建静态 import。

## 缓存

```ts
cache: {
  directory: '.amamo-mdx/cache',
}
```

缓存键是 BLAKE3 digest，输入包括缓存格式、原生 crate 版本、OS、架构、目标模式、归一化配置
和运行时包版本、源码路径和字节，以及已启用的 `lastModified` 值。命中缓存还要求之前记录的
所有媒体依赖仍然存在。

损坏记录会被删除并重新编译，同时产生 `AMAMO_CACHE_CORRUPT` warning。成功的完整构建会清理
已经不再被发现内容引用的记录。

设置 `cache: false` 可关闭持久化记录。直接 API 和 Vite 仍可编译，但 Next loader 没有缓存
文件就无法工作。

## 生成产物

```ts
generatedDirectory: '.amamo-mdx'
```

编译器固定在这里写三个共享产物：

- `collections.mjs`
- `collections.d.ts`
- `index.json`

缓存和 manifest 位置彼此独立。集合、缓存、生成目录和 manifest 的相对配置路径从 `root` 解析，
而 Markdown 媒体路径从所在源文档解析。`root` 默认是 `process.cwd()`；已存在的 root 和集合
目录会在归一化时 canonicalize。只要配置可能从其它工作目录加载，就应显式设置 `root`。
