Search by

markup-carve / symfony-carve

dereuromark

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!

dereuromark

Statistics

Installs: 54

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.1.5 2026-09-20 10:04 UTC

This package is auto-updated.

Last update: 2026-09-22 15:37:23 UTC


README

CI PHP License

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

Carve is a lightweight markup language for structured documents, with clear, consistent 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*');
    $text = $carve->renderText('# Hello *world*');
    $markdown = $carve->renderMarkdown('# Hello *world*');

    return new Response($html);
}

Twig

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

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

{# plain text and Markdown filters (escaped normally by Twig) #}
{{ article.body|carve_text }}
{{ article.body|carve_markdown }}

Only the HTML output from carve is marked safe, so Twig does not double-escape it. The carve_text and carve_markdown filters are not HTML and Twig escapes them normally. Safe mode only affects HTML rendering; profiles apply to all three output formats.

Configuration

# config/packages/carve.yaml
carve:
    safe_mode: true      # sanitize HTML (default: true)
    raw_html: strip      # strip | escape | allow (default: strip)
    profile: null        # null | full | article | comment | minimal (default: null)
    diagrams: []         # diagram presets to enable (default: none)
    include_root: null   # absolute trusted filesystem root (default: off)
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.
profile enum|null null Restrict markup features using full, article, comment, or minimal.
diagrams string[] [] Diagram fenced-block presets to enable (see below). Off by default.
include_root string|null null Absolute containment root for file-backed rendering.

Setting safe_mode: false disables sanitization entirely. Only do this for fully trusted input. Safe mode only affects HTML output. Profiles restrict available constructs for HTML, plain-text, and Markdown output; null leaves all constructs available.

File includes

Twig filters and CarveRenderer::render() accept anonymous strings, so they never read files. Set an absolute include_root and call the explicit file API for trusted, file-backed content:

$report = $renderer->renderFileWithReport('/srv/docs/book/main.crv');
$html = $report['value'];
$warnings = $report['warnings'];
$dependencies = $report['dependencies'];

renderFile() is the HTML-only convenience form. Relative includes resolve from the file containing each directive and cannot traverse or follow a symlink outside the configured root. Warning reports omit resolver details and replace outside paths before they reach the optional PSR logger.

include_root has to be an absolute path, and the renderer refuses a relative one rather than resolving it against the working directory, which is arbitrary with respect to the document.

The dependency list contains resolved and attempted targets. Applications that cache rendered HTML must include those identities in their invalidation policy, including missing targets, so creating a formerly missing file invalidates its parent. The bundle does not prescribe a cache implementation.

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