npm package: @rendou/core
Description: Zero-config Markdown-to-React compiler for React and Next.js apps.
Author: Vladyslav Dobrodii
Latest version: 1.0.1

# @rendou/core

Zero-config Markdown-to-React compiler for React and Next.js apps.

- **Frontmatter extraction**: parse YAML metadata out of your `.md` files.
- **GFM & HTML**: support GitHub-flavored Markdown and inline HTML.
- **Shiki syntax highlighting**: beautiful, themeable code blocks.
- **Robust error handling**: `MarkdownError` for missing files or parse failures.

## Installation

```bash
# npm
npm install @rendou/core

# Yarn
yarn add @rendou/core

# pnpm
pnpm add @rendou/core
```

## Quick Start

Below is a minimal example showing how to use `@rendou/core` in a Next.js App Router dynamic route `[...slug]` to compile and render Markdown files on the fly. This page component will match any nested path, e.g. `/blog/artists/steve-jobs` → `slug = ['blog','artists', 'steve-jobs']`. We handle missing files with `notFound()` and demonstrate how to access frontmatter metadata.

```ts
// app/[...slug]/page.tsx

import { compileMarkdownFile, MarkdownError } from '@rendou/core';

async function demo({ params }: { params: Promise<{ slug: string[] }> }) {
  try {
    const { slug } = await params;
    const { frontmatter, content, toc } = await compileMarkdownFile(
      slug,
      'content', // Optional: defaults to 'content' if omitted
    );
    return (
      <>
        {/* Example: display a title from frontmatter */}
        {frontmatter.title && <h1>{frontmatter.title}</h1>}

        {/* Render Table of Contents */}
        {toc.length > 0 && (
          <nav>
            <ul>
              {toc.map((item, index) => (
                <li key={index} style={{ marginLeft: (item.depth - 1) * 16 }}>
                  <a href={`#${item.id}`}>{item.text}</a>
                </li>
              ))}
            </ul>
          </nav>
        )}

        {/* Render the transformed Markdown content */}
        <article>{content}</article>
      </>
    )
  } catch (err) {
    if (err instanceof MarkdownError && err.code === 'ENOENT') {
      notFound();
    } else {
      throw err;
    }
  }
}
```

## API

```ts
async function compileMarkdownFile<
  FM extends Record<string, unknown> = Record<string, unknown>,
>(slug: string[], contentDir: string = 'content'): Promise<CompileResult<FM>>;
```

#### Parameters

- `slug: string[]` — path segments (no file extension).
- `contentDir?: string` — directory where .md files live (defaults to "content").

#### Returns

```ts
interface CompileResult<FM> {
  frontmatter: FM;
  toc: TocItem[];
  content: ReactNode;
}
```

#### Types

```ts
// src/types.ts

export interface CompileResult<FM> {
  frontmatter: FM;
  toc: TocItem[];
  content: ReactNode;
}

export interface TocItem {
  depth: number; // heading level (e.g. 1 for h1)
  text: string; // heading text
  id: string; // generated id for linking
}
```

#### Errors

- `MarkdownError('ENOENT', …)` — file not found.
- `MarkdownError('PARSE', …)` — parse or transform failure.

### MarkdownError

```ts
export class MarkdownError extends Error {
  constructor(
    public code: 'ENOENT' | 'PARSE',
    message?: string,
  ) {
    super(message);
    this.name = 'MarkdownError';
  }
}
```

## Plugins

Syntax highlighting via `remarkShiki` with `slack-dark` theme in `shared/plugins/remarkShiki.ts`.

## License

This project is licensed under the MIT License.

## Contact

**Vladyslav Dobrodii**

- [dobrodii.vlad200@gmail.com](mailto:dobrodii.vlad200@gmail.com)
- [LinkedIn](https://www.linkedin.com/in/vladyslav-dobrodii-20384a233/)
- [GitHub](https://github.com/dladislav201/)