---
description: Build a complete content set, apply incremental updates, inspect results, and dispose compiler resources.
---

# Compiler API

Use `createCompiler` when your own script or build system should own the lifecycle. Vite and Next
share the same compiler behavior, but each created instance keeps its own records, queue, and
highlighter.

## Create and close a compiler

```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()
}
```

Creation normalizes the config and initializes Shiki when highlighting is enabled. The native
binding is loaded on the first `build()` or `transform()` that needs a native batch.

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

Operations on one compiler are serialized. Concurrent `build()` calls share one in-flight build;
incremental operations wait their turn.

## `build()`

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

A full build:

1. Walks every collection in deterministic order.
2. Derives locale, slug, and key metadata and rejects duplicate keys.
3. Reads every source and optional last-modified value.
4. Reuses compatible cache records or runs the Rust/Shiki compile pipeline.
5. Replaces the compiler's complete in-memory record set.
6. Writes changed manifests and shared generated files, then prunes stale cache entries.

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

`outputsWritten` counts files whose bytes changed. An unchanged warm build can report zero and leave
all output modification times untouched. Cache-record writes are not included in this count.

## `transform(file)`

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

`transform` compiles one recognized collection file, replaces its record, rewrites affected shared
outputs, and prunes cache records no longer in the compiler's current state.

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

- `code` is the compiled JavaScript module body.
- `map` is currently always `null`.
- `record.frontmatter` contains the complete validated frontmatter object.
- `record.derived` contains enabled reading-time and last-modified values.
- `record.hash` is the BLAKE3 digest of the source bytes.
- `record.cacheKey` also includes config, platform, path, and optional modification metadata.
- `record.diagnostics` contains successful warnings such as missing media under the `warn` policy.

Use absolute paths. Relative paths resolve from the process working directory, not automatically
from `config.root`.

> Run `build()` first when shared outputs must retain every document. Calling `transform()` on a new
> compiler creates state containing only that transformed file.

## `remove(file)`

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

`remove` deletes a record already known to this compiler, updates shared outputs, prunes the cache,
and returns the number of changed output files. An unknown path is a no-op returning `0`.

## `dispose()`

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

Disposal releases compiler resources and Shiki. It is idempotent. Any later build, transform, or
remove call rejects with `AMAMO_COMPILER_DISPOSED`.

## Errors and diagnostics

Different boundaries fail differently:

- Invalid object schemas or non-schema configuration data throw `TypeError` with an
  `AMAMO_CONFIG_*` code in the message.
- Native parsing, schema, media, cache, and manifest failures become an error named
  `AmamoMdxError` with a `diagnostics` array.
- Shiki setup and unknown-language failures are ordinary `Error` values.
- Filesystem, watcher, and Next loader failures are ordinary `Error` values.

`IDiagnostic` is exported from `@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'
}
```

The shape reserves `range` and `hint`, but they are currently omitted. A batch stops at the first
failing document or stage rather than aggregating every failure. Schema messages may quote submitted
frontmatter values.

## Shared generated files

After a build, `generatedDirectory` contains:

- `collections.mjs` — sorted arrays of `{ derived, frontmatter, key, locale, slug, load }`.
- `collections.d.ts` — a companion declaration output for the registry.
- `index.json` — source path, cache key, cache directory, and config fingerprint for the Next loader.

The registry's `load()` functions import the original MDX sources. A host bundler still needs the
Vite plugin, Next loader, or another compatible MDX transform.
