Skip to content

About

No description, website, or topics provided.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

mdd-engine

The headless Markdown documentation compiler behind mdd. Give it a local project; get validated pages, navigation, assets, and article HTML that any frontend can consume.

Built with TypeScript and Bun. Runs on Node.js 22, 24, and 26 without Bun. The default is the latest Node LTS, currently pinned to 24.21.0.

Build Flow's default channels publish development, PR, and manual preview packages alongside regular releases to npm and GitHub Packages. See build channels and releasing.

A documentation project

my-project/
  mdd/
    config.json           # optional
    footer.md             # optional shared social links
    contents/
      index.md            # required homepage
      get-started/
        installation.md
      assets/
        logo.png
    themes/
      custom/
        theme.css
        theme.js          # optional; engine never executes it

Ordinary Markdown works without configuration. Folder names become routes and navigation groups. For example, get-started/installation.md becomes /get-started/installation/; a folder's index.md becomes its landing page.

{
  "title": "My Project",
  "paths": { "contents": "./contents", "themes": "./themes" },
  "theme": "custom"
}

All settings are optional. Custom paths are relative to mdd/config.json and must stay within the checkout. Selecting a custom theme requires its theme.css. The engine returns theme file locations for the website layer to apply. Plugin loading is deferred.

Compile without a website

Install the regular package with bun add @wgtechlabs/mdd-engine. After a successful preview publication, use bun add @wgtechlabs/mdd-engine@dev for development builds or bun add @wgtechlabs/mdd-engine@pr for PRs targeting dev. Preview tags track the most recently published package in their channel; install an exact version to test a particular PR. You can also install a locally packed copy.

In your Node project:

import { compileProject } from '@wgtechlabs/mdd-engine';

const result = await compileProject({
  projectDir: '/absolute/path/to/my-project',
  mddDir: 'mdd',
  basePath: '/docs/'
});

if (!result.site) {
  console.error(result.diagnostics);
  process.exitCode = 1;
} else {
  console.log(result.site.pages[0].html);
}

site is absent whenever authoring errors exist. Diagnostics contain a stable code, severity, message, and source location where available. Unexpected filesystem failures reject the promise with context. Identical inputs produce identical output.

Excessive Markdown nesting that exceeds the runtime's call stack produces a CONTENT_TOO_DEEP diagnostic identifying the source file.

The result includes:

  • pages: source, route, public URL, title, description, article HTML, readable Markdown, headings, and navigation metadata.
  • navigation: sorted folder/page tree, with optional landing URLs.
  • assets: referenced content files with checkout-relative sources, documentation-root-relative destinations, and public URLs.
  • theme: the built-in default or selected theme file locations.
  • footer: optional shared footer source and validated social-link data.

Paths in the model use forward slashes. Resolve sources against the same projectDir used to compile. Asset destinations are filesystem paths, while asset URLs and page routes are URL-encoded. Decode page-route segments when deriving output directories. Prefix asset destinations with the documentation output directory when exporting; do not prefix them with a GitHub repository name a second time. The engine emits no files and starts no server.

Headless search

Build a serializable index from a successful compilation:

import { createSearchIndex } from '@wgtechlabs/mdd-engine';
import { search } from '@wgtechlabs/mdd-engine/search';

const index = createSearchIndex(result.site);
const restored = JSON.parse(JSON.stringify(index));
console.log(search(restored, 'installation', { limit: 10 }));
// Multiple heading hits, breadcrumbs, and ranges for UI highlights.
console.log(search(restored, 'instalation', {
  mode: 'sections', fuzzy: true, limit: 8,
}));
// [{ title, url, section?, excerpt, score }]

The dependency-free /search entry point works in browsers and Node. Results reuse compiled page URLs and heading anchors, respect the public base path, and contain plain text for the consuming interface to display safely. MDD owns exporting/loading the index and presenting search controls. See search matching, limits, and validation.

Shared social footer

Write social links once in mdd/footer.md:

:::socials
- [GitHub](https://github.com/wgtechlabs)
- [Community](https://example.org/community)
:::

The engine returns these as site.footer.socials, with plain labels and validated absolute HTTPS URLs. It does not render a footer or select icons. MDD composes the main footer and its theme styles it. This file is excluded from pages, navigation, and search; socials is not an article component. See the footer format and boundaries.

Markdown and components

Supported Markdown includes headings, lists, code fences, links, images, GFM tables, task lists, and strikethrough. Optional YAML frontmatter supports title, description, navTitle, and finite numeric order:

---
title: Install mdd
navTitle: Installation
order: 1
---
# Installation

> [!NOTE]
> **Before you start**
>
> You need a local documentation project.

:::details[More information]
Ordinary **Markdown** works inside components.
:::

Use GitHub-style alerts with NOTE, TIP, IMPORTANT, WARNING, or CAUTION. Put the exact uppercase marker on the opening line of a blockquote at the document root; nested blockquotes remain ordinary quotes. Alerts become semantic aside elements with mdd-alert and mdd-<type> classes. Their readable Markdown preserves the > [!TYPE] marker. The engine supplies meaning and labels; the reader composes the article, and themes supply icons and colors.

:::details[More information] remains supported and becomes details/summary; its label is optional, attributes are errors, and its readable Markdown uses a blockquote with a bold label. The old :::note, :::tip, and :::warning directives now fail with a REMOVED_COMPONENT migration diagnostic. See alerts and migration for all five types, theme hooks, and how to preserve custom titles and bodies.

Document an API endpoint with a leaf directive, then use ordinary Markdown for parameters and request/response examples:

## Retrieve a widget

::endpoint{method="GET" path="/v1/widgets/{id}"}

| Parameter | Type | Description |
| --- | --- | --- |
| `id` | string | Widget identifier. |

The required method accepts GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE, or CONNECT, normalizing lowercase/mixed case to uppercase. The required path starts with a single / and contains no whitespace or control characters; braces and query punctuation remain literal text. Labels, extra attributes, and inline/container forms are errors. The engine emits a div.mdd-endpoint containing strong.mdd-endpoint-method.mdd-method-get (or the corresponding lowercase method) and code.mdd-endpoint-path. Normalized Markdown contains **GET** followed by the code-formatted path, so the signature stays readable and searchable. Endpoint paths are not rewritten with the documentation base path. This is documentation only: no HTTP requests run. MDD and its themes provide presentation.

Title precedence is frontmatter title, first H1, then readable filename. Navigation uses navTitle when supplied. Explicit order sorts first; remaining siblings sort deterministically by label and path.

Local .md links, extensionless routes, reference links, and images resolve from their source document. A leading slash addresses the documentation root. basePath prefixes public links, including /docs/ and /repository/docs/. When a file-style URL matches both an existing supported asset and a page route, the asset wins: chart.png selects the image, while /chart.png/ explicitly selects the page. If no regular asset exists, dotted page routes still resolve. External links are preserved without network requests. Headings have mdd--prefixed GitHub-style slugs; author links such as #installation are rewritten to #mdd-installation. Duplicate headings receive -1, -2, and subsequent suffixes.

Reference definitions follow Markdown's first-definition-wins rule. Unused definitions and unreferenced footnotes are omitted from normalized output and do not contribute assets, headings, or link-validation errors. Referenced footnotes, including notes reached through other notes, retain their content and validation.

Content boundaries

Raw HTML, executable URL schemes, path escapes, unknown configuration, missing local targets, and route collisions fail compilation. MDX is not evaluated; expressions are inert Markdown text, and JSX-style HTML is rejected. Hidden/sensitive paths are excluded. Content discovery rejects symlinks to avoid aliases and traversal; configured roots are resolved and checked against the checkout. Source files must remain stable while compilation and export run.

Referenced content assets are limited to PNG, JPEG, GIF, WebP, AVIF, ICO, PDF, and plain text. SVG, HTML, JavaScript, and CSS are not content assets in this first version. Custom theme CSS/JavaScript is declared separately and must be treated as trusted by the website layer. Asset bytes are not transformed or sanitized; hosts should serve correct media types with nosniff and downloads with suitable disposition.

Generated paths _assets/, _mdd/, markdown/, mdd-build.json, llms.txt, robots.txt, sitemap.xml, and 404.html are reserved. Keep generated output outside the content root.

A complete example project is included under examples/basic. Pass that directory as projectDir to compile it.

Develop

nvm use
bun install --frozen-lockfile
bun run check
bun run coverage
bun audit

bun run build emits Node ESM and TypeScript declarations to dist/. bun run smoke creates a package archive, installs it into an isolated consumer, and runs it with the current Node binary. It checks compilation, footer data, and serialized search at all three base paths without Bun in the runtime, and bundles the isolated search entry for browsers. On POSIX systems, MDD_TEST_NODE_BINARIES can contain colon-separated Node binary paths to exercise the same archive across versions.

Follow Clean Workflow, contributing, and the engine contract. See verification for the checks performed during bootstrap.

License

Licensed under the MIT License.

About

No description, website, or topics provided.

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages