markup-carve / symfony-carve
Symfony bundle to render Carve markup to HTML via carve-php.
Package info
github.com/markup-carve/symfony-carve
Type:symfony-bundle
pkg:composer/markup-carve/symfony-carve
Fund package maintenance!
Requires
- php: ^8.2
- markup-carve/carve-php: ^0.1.3
- symfony/config: ^6.4 || ^7.0
- symfony/dependency-injection: ^6.4 || ^7.0
- symfony/http-kernel: ^6.4 || ^7.0
Requires (Dev)
- php-collective/code-sniffer: ^0.6.0
- phpstan/phpstan: ^2.0
- phpunit/phpunit: ^11.0 || ^12.0 || 13.0
- symfony/framework-bundle: ^6.4 || ^7.0
- symfony/twig-bundle: ^6.4 || ^7.0
- twig/twig: ^3.0
Suggests
- symfony/twig-bundle: To use the {{ value|carve }} Twig filter and carve() function
This package is auto-updated.
Last update: 2026-07-27 20:09:52 UTC
README
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(orrenderGraphvizDiagrams/renderD2Diagrams). - PlantUML has no practical in-browser renderer; render it via a Kroki
server with the same package's
renderKrokiDiagramshelper.⚠️ 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'sserveroption 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.
License
MIT
