|
| 1 | +--- |
| 2 | +title: Compiler API |
| 3 | +description: Drive the compiler directly with createCompiler, build, transform, remove, and dispose. |
| 4 | +order: 4 |
| 5 | +--- |
| 6 | + |
| 7 | +The Vite and Next adapters both run on top of the same `ICompiler`. The root API exposes that |
| 8 | +interface so a host application can drive the compiler directly — for example, a build script |
| 9 | +that runs before Vite, a test harness, or a static site generator. |
| 10 | + |
| 11 | +## Construction |
| 12 | + |
| 13 | +```ts |
| 14 | +import { createCompiler } from '@amamo/mdx' |
| 15 | +import config from './amamo.config.js' |
| 16 | + |
| 17 | +const compiler = await createCompiler(config) |
| 18 | +``` |
| 19 | + |
| 20 | +`createCompiler` is async because it loads the native binding and the configured highlighter. The |
| 21 | +config is normalized on construction; later edits are not picked up. |
| 22 | + |
| 23 | +The returned object implements `ICompiler`: |
| 24 | + |
| 25 | +```ts |
| 26 | +interface ICompiler { |
| 27 | + build(): Promise<IBuildResult> |
| 28 | + dispose(): Promise<void> |
| 29 | + remove(file: string): Promise<number> |
| 30 | + transform(file: string): Promise<ITransformResult> |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +## build |
| 35 | + |
| 36 | +```ts |
| 37 | +const result = await compiler.build() |
| 38 | +``` |
| 39 | + |
| 40 | +Discovers every collection, parses and validates every record, renders code blocks, prunes the |
| 41 | +cache, and writes the generated module, the private loader index, and every configured manifest. |
| 42 | +The compiler coalesces concurrent calls, so calling `build()` twice in quick succession is safe. |
| 43 | + |
| 44 | +```ts |
| 45 | +interface IBuildResult { |
| 46 | + cached: number |
| 47 | + compiled: number |
| 48 | + discovered: number |
| 49 | + outputsWritten: number |
| 50 | +} |
| 51 | +``` |
| 52 | + |
| 53 | +- `discovered` is the number of MDX files found across all collections. |
| 54 | +- `compiled` is the number of files that produced fresh cache records. |
| 55 | +- `cached` is `discovered - compiled`. |
| 56 | +- `outputsWritten` is the number of generated files actually written; the rest were byte-for-byte |
| 57 | + identical to the existing output and left untouched. |
| 58 | + |
| 59 | +`build()` is a superset of the work the adapters do at startup. Calling it explicitly is useful |
| 60 | +when the generated module is consumed by code that is not the Vite or Next adapter. |
| 61 | + |
| 62 | +## transform |
| 63 | + |
| 64 | +```ts |
| 65 | +const result = await compiler.transform('content/posts/hello.mdx') |
| 66 | +``` |
| 67 | + |
| 68 | +Re-parses a single file, validates its frontmatter, and writes any new generated output that |
| 69 | +depends on it. The result is the freshly compiled record and a `cached` flag that mirrors the |
| 70 | +cache behavior of the underlying batch. |
| 71 | + |
| 72 | +```ts |
| 73 | +interface ITransformResult { |
| 74 | + cached: boolean |
| 75 | + code: string |
| 76 | + map: null |
| 77 | + outputsWritten: number |
| 78 | + record: IDocumentRecord |
| 79 | +} |
| 80 | +``` |
| 81 | + |
| 82 | +`code` is the JavaScript source the host application should treat as the document's module body. |
| 83 | +`map` is currently always `null`; the compiler reserves the field for a future source map. The |
| 84 | +full `record` exposes the parsed frontmatter, the derived fields, the diagnostics, the cache key, |
| 85 | +and the SHA-256 hash of the input bytes. |
| 86 | + |
| 87 | +`transform` rejects with an `AmamoMdxError` whose `diagnostics` field lists every problem the |
| 88 | +compiler found. Frontmatter schema violations, missing media, and unknown code-block languages all |
| 89 | +surface as diagnostics. |
| 90 | + |
| 91 | +## remove |
| 92 | + |
| 93 | +```ts |
| 94 | +const removed = await compiler.remove('content/posts/deleted.mdx') |
| 95 | +``` |
| 96 | + |
| 97 | +Removes a file from the cache and rewrites any generated output that referenced it. Returns the |
| 98 | +number of generated files actually rewritten. Calling `remove` on a path that is not part of any |
| 99 | +collection is a no-op and returns `0`. |
| 100 | + |
| 101 | +`remove` is the delete-side counterpart of `transform`. The Vite and Next adapters wire it to the |
| 102 | +underlying file system watcher. |
| 103 | + |
| 104 | +## dispose |
| 105 | + |
| 106 | +```ts |
| 107 | +await compiler.dispose() |
| 108 | +``` |
| 109 | + |
| 110 | +Releases the highlighter and any open file handles. After `dispose`, the compiler is unusable; |
| 111 | +calling any other method rejects. The compiler is also a process-wide singleton from the adapter's |
| 112 | +point of view, so do not share a disposed instance across requests. |
| 113 | + |
| 114 | +## Errors and diagnostics |
| 115 | + |
| 116 | +Most failures are not thrown as JavaScript exceptions; they are returned as `IDiagnostic[]` |
| 117 | +inside an `AmamoMdxError`: |
| 118 | + |
| 119 | +```ts |
| 120 | +class AmamoMdxError extends Error { |
| 121 | + readonly diagnostics: IDiagnostic[] |
| 122 | +} |
| 123 | + |
| 124 | +interface IDiagnostic { |
| 125 | + code: string |
| 126 | + file?: string |
| 127 | + hint?: string |
| 128 | + message: string |
| 129 | + range?: { start; end } |
| 130 | + severity: 'error' | 'warning' |
| 131 | +} |
| 132 | +``` |
| 133 | + |
| 134 | +The compiler's own plumbing rejects the surrounding `Promise`; it is the caller's job to decide |
| 135 | +whether to surface a single message, a list of file:line diagnostics, or to fail the build. |
| 136 | + |
| 137 | +## Generated module |
| 138 | + |
| 139 | +After `build()` the generated module lives at `<generatedDirectory>/collections.mjs`. It exports |
| 140 | +a tree of named records that the host application can `import` directly. The companion |
| 141 | +`collections.d.mts` provides the same shape to TypeScript. |
| 142 | + |
| 143 | +The private loader index at `<generatedDirectory>/index.json` exposes the same records to the Vite |
| 144 | +and Next adapters without forcing them through the public module — they need a key lookup, not |
| 145 | +the full bundle. |
0 commit comments