Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Carve Php Laravel Package

markup-carve/carve-php

Carve PHP is a fast, extensible parser for the Carve lightweight markup language. It converts Carve documents to clean HTML through a simple API, making it easy to add Markdown-style content rendering to Laravel and other PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install via Composer. The package is Composer-ready:

    composer require markup-carve/carve-php
    

    It is a small, low-dependency library, so there is usually no service provider or facade to register — a plain use statement is enough.

  2. Read these first, in order:

    • README.md for the canonical parse/render call.
    • src/ for the public entry class (typically a parser plus a separate HTML renderer) and the list of supported node types.
    • tests/ for executable examples of every supported construct — this is the most reliable documentation for a package with a small user base.
  3. Smallest working call. The exact class names must be confirmed in src/, but the shape is a parse-then-render pipeline:

    use Carve\Carve; // verify namespace/class against README or src/
    
    $html = Carve::parse($post->body)->render();
    
  4. First use case: rendering a trusted prose column (blog post, docs page, changelog) to HTML in a Blade view. Wrap the call once, put it behind {!! !!}, and you have a working pipeline in a few lines. Do not start with user-submitted content — settle the sanitization story first (see Gotchas).

Implementation Patterns

Wrap the parser behind a helper or Blade directive. Avoid scattering parser calls through controllers and views. A single entry point keeps options, caching, and sanitization in one place:

// app/Support/Carve.php
public static function toHtml(string $text): string
{
    return Carve::parse($text)->render();
}

Then in Blade: {!! \App\Support\Carve::toHtml($post->body) !!}.

Cache the rendered HTML, not the parse. Parsing on every request is wasted work for content that changes rarely. Store body_html alongside body and regenerate on save:

protected static	function booted(): void
{
    static::saving(fn ($post) => $post->body_html = Carve::parse($post->body)->render());
}

This also decouples rendering from request time and makes the output searchable/indexable if you want.

Render at the edge, store the source. Keep the Carve source as the system of record. If you later swap renderers, add extensions, or fix an escaping bug, you can re-render everything from source; you cannot reverse HTML back into markup.

Post-process the AST for features HTML alone can't give you. A parse → tree → render pipeline means you can walk the tree before rendering to add heading IDs and anchor links, lazy-load images, rewrite relative URLs, or wrap tables in scroll containers. This is the cleanest integration point and avoids fragile regex over final HTML.

Use extensions for repeated domain constructs. Callouts, embeds, and video shortcodes are better expressed as a custom node plus a renderer than as raw HTML embedded in prose. Check the package's extension registration mechanism in src/ — this is where the "extensible design" pays off.

Serve it through an API resource consistently. If the frontend and API both render content, return the same rendered HTML (or the same AST-derived JSON) from one place. Two pipelines will drift.

Test with golden files. Keep paired input/output fixtures for the constructs you rely on. Because Carve is Markdown-inspired rather than Markdown-compatible, this suite is also your migration safety net if you import existing content.

Gotchas and Tips

  • This is a small, young ecosystem — treat it accordingly. With a handful of stars and no known dependents, pin an exact version, read the source before relying on a feature, and be prepared to vendor or fork. There is no large community to catch regressions for you.
  • Carve ≠ Markdown. Do not assume CommonMark input renders identically. Run your existing Markdown corpus through the parser and diff the output before migrating any content.
  • Raw HTML passthrough is an XSS vector. If the parser passes raw HTML through (most Markdown-family parsers do), user-submitted content is dangerous. Sanitize the rendered output with a dedicated HTML sanitizer, or disable raw HTML in the parser if the option exists. Do not rely on Blade escaping — you will be using {!! !!}.
  • Be deliberate about {!! !!}. The output is intentionally unescaped HTML; the escaping decision must happen inside your wrapper, not at each call site.
  • UTF-8 and mbstring. Multibyte input plus string offsets is a classic source of mangled output. Ensure mbstring is installed and that your database columns and connection charset are UTF-8.
  • Configuration lives in code or constructor options, not necessarily a published config file. Do not assume php artisan vendor:publish exists. Check the source for option names; extension/feature flags in small packages are often undocumented and differ between releases.
  • Debug by inspecting the AST. When output surprises you, dump the parsed tree before rendering. Most "wrong HTML" issues are actually "wrong parse," and the tree tells you immediately which.
  • Watch for a missing trailing newline or block-boundary quirks. Small parsers often have edge cases around the final block, nested lists, or adjacent inline constructs. Add fixtures for the exact shapes your content uses rather than testing the spec in general.
  • Treat the release cadence as a signal. Verify the version constraint in composer.json resolves to the release you expect, and add the package to your dependency-update routine. A future-dated release in package metadata is worth confirming against the repository tags before you lock it in.
  • Extension points are your escape hatch. For anything the parser mishandles, prefer a custom node/renderer over string post-processing of the HTML — post-processing tends to break on nested structures and attributes.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names