markup-carve/symfony-carve

Symfony bundle to render Carve markup to HTML via carve-php.

Maintainers

Package info

github.com/markup-carve/symfony-carve

Type:symfony-bundle

pkg:composer/markup-carve/symfony-carve

Transparency log

Fund package maintenance!

dereuromark

Statistics

Installs: 22

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.2 2026-07-27 20:07 UTC

This package is auto-updated.

Last update: 2026-07-27 20:09:52 UTC


README

CI PHP License

Symfony bundle that renders Carve markup to HTML using carve-php.

Carve is "Djot minus the footguns": a lightweight markup language with consistent, unambiguous syntax.

Installation

composer require markup-carve/symfony-carve

Register the bundle (Symfony Flex does this automatically; otherwise add it to config/bundles.php):

return [
    // ...
    MarkupCarve\SymfonyCarve\CarveBundle::class => ['all' => true],
];

Usage

Service

use MarkupCarve\SymfonyCarve\CarveRenderer;

public function show(CarveRenderer $carve): Response
{
    $html = $carve->render('# Hello *world*');

    return new Response($html);
}

Twig

{# filter #}
{{ article.body|carve }}

{# function #}
{{ carve('# Inline /snippet/') }}

Output is marked safe, so Twig does not double-escape it. The renderer sanitizes input according to the configured safe mode before that point.

Configuration

# config/packages/carve.yaml
carve:
    safe_mode: true      # sanitize HTML (default: true)
    raw_html: strip      # strip | escape | allow (default: strip)
    diagrams: []         # diagram presets to enable (default: none)
Key Type Default Description
safe_mode bool true Enable HTML sanitization. Keep this on for untrusted input.
raw_html enum strip How raw HTML is handled when safe_mode is on: strip, escape, allow.
diagrams string[] [] Diagram fenced-block presets to enable (see below). Off by default.

Setting safe_mode: false disables sanitization entirely. Only do this for fully trusted input.

Diagrams

By default a fenced block like ``` plantuml renders as a plain code block. Listing a preset under diagrams turns that fence into a hydration element for a client-side renderer:

# config/packages/carve.yaml
carve:
    diagrams: ['plantuml', 'mermaid']

Now ``` plantuml renders as <pre class="plantuml">...</pre> and ``` mermaid as <pre class="mermaid">...</pre>, ready for a browser library to pick up.

Preset Fence word(s) Output
mermaid mermaid <pre class="mermaid">
plantuml plantuml, puml <pre class="plantuml">
d2 d2 <pre class="d2">
graphviz dot, graphviz <pre class="graphviz">
wavedrom wavedrom <pre class="wavedrom">
vega_lite vega-lite <div class="vega-lite"><script type="application/json">
chart chart <div class="chart"><script type="application/json">
abc abc <pre class="abc">

The bundle only emits the markup - it does not ship or load any renderer. You supply the client side:

  • Graphviz, D2 render fully offline (no server, no external call) with the WebAssembly helpers from @markup-carve/carve-grammars: renderDiagrams (or renderGraphvizDiagrams / renderD2Diagrams).
  • PlantUML has no practical in-browser renderer; render it via a Kroki server with the same package's renderKrokiDiagrams helper.

    ⚠️ Privacy / GDPR: the default Kroki server is the public https://kroki.io, so the PlantUML source is sent to a third party outside your domain. For sensitive content, or to stay offline, point the helper's server option at a self-hosted or localhost Kroki, and disclose the external call to end users where required.

  • Mermaid, WaveDrom, Vega-Lite, Chart.js, ABC each need their own browser library loaded on the page (mermaid.js, wavedrom, vega-embed, chart.js, abcjs).

Unknown names in the whitelist are rejected by config validation; the accepted values are exactly the presets above.

Demo

A full runnable demo app lives at symfony-carve-demo: the Twig filter and function, the CarveRenderer service, a live editor, a safe-mode comparison, and a syntax gallery.

symfony-carve demo

License

MIT