@markup-carve/astro-carve
v0.1.0
Published
Astro integration for the Carve markup language - use .crv files as pages and imports, rendered to HTML via carve-js
Maintainers
Readme
astro-carve
An Astro integration for the
Carve markup language. It lets you
author content in .crv files and render it to HTML at build time
with carve-js
(@markup-carve/carve).
Install
npm install @markup-carve/astro-carveastro is a peer dependency. carve-js (@markup-carve/carve) is a regular
dependency, installed from npm, so the command above is all that is needed.
Usage
Add the integration to your Astro config:
// astro.config.mjs
import { defineConfig } from 'astro/config'
import carve from '@markup-carve/astro-carve'
export default defineConfig({
integrations: [carve()],
})Author a Carve document, for example src/content/doc.crv:
---
title: Carve in Astro
---
# Carve in Astro
A paragraph with *bold*, /emphasis/, and _underline_.
- one
- twoImport it into an .astro page and render the HTML:
---
import html, { frontmatterData } from '../content/doc.crv'
const title = frontmatterData.title ?? 'Carve page'
---
<html lang="en">
<head><title>{title}</title></head>
<body>
<main set:html={html} />
</body>
</html>The build emits the carve-js-rendered HTML into your static output.
What a .crv import exports
Each .crv module exports:
| Export | Type | Description |
| ----------------- | ------------------------------------------ | -------------------------------------------------------- |
| default | string | The rendered HTML (same value as html). |
| html | string | The carve-js-rendered HTML. |
| source | string | The raw Carve source. |
| frontmatter | { format, content } \| null | Raw frontmatter as Carve exposes it (verbatim, unparsed).|
| frontmatterData | Record<string, unknown> | Simple key: value frontmatter parsed to scalars. |
Carve does not interpret frontmatter itself. frontmatterData is a small,
dependency-free reader for flat scalar metadata (title, draft, numbers,
quoted strings). For structured YAML, run your own parser over
frontmatter.content.
Options
carve({
// Which module ids count as Carve. Default: /\.crv$/
include: /\.crv$/,
// Forwarded to carve-js carveToHtml (extensions, heading-id options, ...).
render: {},
// Parse simple key: value frontmatter into frontmatterData. Default true.
parseFrontmatter: true,
// Register .crv as Astro page extensions. Default false. See below.
pageExtensions: false,
})All carve-js render/parse options (including extensions for Tier-2 syntax)
pass through render.
Integration surfaces
- Verified and supported: importing a
.crvfile into an.astropage or component (import html from './doc.crv'). The example project builds this with a realastro buildand the rendered Carve HTML appears in the static output. - Off by default: page-extension routes (
pageExtensions: true). Astro 7 exposes an unstableaddPageExtensionhook, and the integration will call it when this option is on. However, registering the extension makes Astro render asrc/pages/*.crvfile as an Astro component; this integration's transform emits a plain HTML-string module, not an Astro component factory, so a registered.crvroute renders an empty shell rather than the Carve HTML. A true page route would need a content-entry-type / renderer that emits an Astro-component-compatible module. Until that exists, use the.astroimport surface for page routes.
Vite plugin (standalone)
The transform is also exported as a standalone Vite plugin, so it works in any Vite app, not only Astro:
import { carveVitePlugin } from '@markup-carve/astro-carve'
export default {
plugins: [carveVitePlugin()],
}TypeScript
Add an ambient declaration so .crv imports are typed:
// src/carve.d.ts
declare module '*.crv' {
export const source: string
export const html: string
export const frontmatter: { format: string; content: string } | null
export const frontmatterData: Record<string, unknown>
const _default: string
export default _default
}