import { test, expect } from 'bun:test';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { createCompiler, parseBlocks } from '../index.js';
const fixturesDir = resolve(import.meta.dir, '../../../fixtures/core');
function readFixture(path: string): string {
return readFileSync(resolve(fixturesDir, path), 'utf8');
}
const compiler = createCompiler({});
// ── Markdown path snapshots ─────────────────────────────────────────────
test('snapshot: hello.md', () => {
const source = readFixture('markdown/hello.md');
const result = compiler.compile(source, '/hello.md', {});
expect(result.code).toMatchSnapshot();
expect(result.headings).toMatchSnapshot();
});
test('snapshot: table.md', () => {
const source = readFixture('markdown/table.md');
const result = compiler.compile(source, '/table.md', {});
expect(result.code).toMatchSnapshot();
});
test('snapshot: slug_duplicates.md', () => {
const source = readFixture('markdown/slug_duplicates.md');
const result = compiler.compile(source, '/slug_duplicates.md', {});
expect(result.code).toMatchSnapshot();
expect(result.headings).toMatchSnapshot();
});
test('snapshot: footnotes.md', () => {
const source = readFixture('markdown/footnotes.md');
const result = compiler.compile(source, '/footnotes.md', {});
expect(result.code).toMatchSnapshot();
expect(result.headings).toMatchSnapshot();
});
test('snapshot: gfm_full.md', () => {
const source = readFixture('markdown/gfm_full.md');
const result = compiler.compile(source, '/gfm_full.md', {});
expect(result.code).toMatchSnapshot();
expect(result.headings).toMatchSnapshot();
});
test('snapshot: aside_directive.md', () => {
const source = readFixture('components/aside_directive.md');
const result = compiler.compile(source, '/aside_directive.md', {});
expect(result.code).toMatchSnapshot();
});
// ── Directive rendering ─────────────────────────────────────────────────
test('snapshot: directives with attributes', () => {
const source = `:::note[Important Notice]
This is **important** content with a [link](https://example.com).
:::
:::warning
Be careful!
:::
:::tip{id="my-tip"}
A tip with attributes.
:::`;
const result = compiler.compile(source, '/directives.md', {});
expect(result.code).toMatchSnapshot();
});
// ── Task list rendering ─────────────────────────────────────────────────
test('snapshot: task lists', () => {
const source = `- [x] Completed task
- [ ] Incomplete task
- Regular list item
1. [x] Ordered checked
2. [ ] Ordered unchecked`;
const result = compiler.compile(source, '/tasklist.md', {});
expect(result.code).toMatchSnapshot();
});
// ── Custom heading IDs ──────────────────────────────────────────────────
test('snapshot: custom heading IDs', () => {
const source = `# First Heading {#custom-first}
## Second Heading
## Second Heading
### Third with **bold** {#bold-heading}`;
const result = compiler.compile(source, '/custom-ids.md', {});
expect(result.code).toMatchSnapshot();
expect(result.headings).toMatchSnapshot();
});
// ── MDX compilation path snapshots ──────────────────────────────────────
test('snapshot: simple MDX compilation', () => {
const source = `---
title: Test
---
# Hello MDX
This is **bold** and *italic*.
- Item 1
- Item 2
`;
const batchResult = compiler.compileMdxBatch(
[{ id: '/test.mdx', source }],
{ continueOnError: false }
);
const result = batchResult.results[0];
expect(result?.error).toBeUndefined();
expect(result?.result?.code).toMatchSnapshot();
expect(result?.result?.headings).toMatchSnapshot();
});
test('snapshot: MDX with task lists', () => {
const source = `# Tasks
- [x] Done
- [ ] Todo
`;
const batchResult = compiler.compileMdxBatch(
[{ id: '/tasks.mdx', source }],
{ continueOnError: false }
);
const result = batchResult.results[0];
expect(result?.error).toBeUndefined();
expect(result?.result?.code).toMatchSnapshot();
});
test('snapshot: MDX with directives', () => {
const source = `# Guide
:::note[Pay Attention]
This is important.
:::
:::warning
Danger ahead!
:::
`;
const batchResult = compiler.compileMdxBatch(
[{ id: '/directives.mdx', source }],
{ continueOnError: false }
);
const result = batchResult.results[0];
expect(result?.error).toBeUndefined();
expect(result?.result?.code).toMatchSnapshot();
});
// ── Batch compilation (MD path) ─────────────────────────────────────────
test('snapshot: compileBatchToModule for markdown', () => {
const source = `# Batch Test
Paragraph with **bold** and [link](https://example.com).
\`\`\`js
const x = 1;
\`\`\`
`;
const batchResult = compiler.compileBatchToModule(
[{ id: '/batch.md', filepath: '/batch.md', source }],
{ continueOnError: false }
);
const result = batchResult.results[0];
expect(result?.error).toBeUndefined();
expect(result?.result?.code).toMatchSnapshot();
expect(result?.result?.headings).toMatchSnapshot();
});
// ── Heading autolinks ───────────────────────────────────────────────────
test('heading autolinks: disabled by default', () => {
const source = '# Hello\n\n## World\n';
const result = compiler.compile(source, '/test.md', {});
expect(result.code).not.toContain(' {
const source = '# Hello\n\n## World {#custom}\n';
const autolinkCompiler = createCompiler({
enableHeadingAutolinks: true,
});
const result = autolinkCompiler.compile(source, '/test.md', {});
expect(result.code).toContain('');
expect(result.code).toContain('');
expect(result.code).toContain('');
});
test('heading autolinks: enabled via parseBlocks', () => {
const source = '# Hello\n\n## World\n';
const result = parseBlocks(source, {
enableHeadingAutolinks: true,
});
const html = result.blocks.map((b: any) => b.content || '').join('');
expect(html).toContain('');
expect(html).toContain('');
});
// ── Custom directives ───────────────────────────────────────────────────
test('custom directives: MDX path with custom component mapping', () => {
const source = '# Test\n\n:::custom-box[Hello]\nContent here\n:::\n';
const customCompiler = createCompiler({
customDirectiveNames: ['custom-box'],
directiveComponentMap: { 'custom-box': 'MyBox' },
});
const batchResult = customCompiler.compileMdxBatch(
[{ id: '/custom.mdx', source }],
{ continueOnError: false }
);
const result = batchResult.results[0];
expect(result?.error).toBeUndefined();
expect(result?.result?.code).toContain('MyBox');
expect(result?.result?.code).toContain('custom-box');
});
test('custom directives: built-in directives still work with custom names', () => {
const source = ':::note[Notice]\nImportant\n:::\n';
const customCompiler = createCompiler({
customDirectiveNames: ['custom-box'],
});
const batchResult = customCompiler.compileMdxBatch(
[{ id: '/builtin.mdx', source }],
{ continueOnError: false }
);
const result = batchResult.results[0];
expect(result?.error).toBeUndefined();
expect(result?.result?.code).toContain('Aside');
});