PHPackages                             markup-carve/carve-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Parsing &amp; Serialization](/categories/parsing)
4. /
5. markup-carve/carve-php

ActiveLibrary[Parsing &amp; Serialization](/categories/parsing)

markup-carve/carve-php
======================

PHP parser for Carve, a human-centered lightweight markup language derived from djot-php.

08343PHPCI passing

Since Jun 18Pushed 4w agoCompare

[ Source](https://github.com/markup-carve/carve-php)[ Packagist](https://packagist.org/packages/markup-carve/carve-php)[ RSS](/packages/markup-carve-carve-php/feed)WikiDiscussions main Synced 3w ago

READMEChangelogDependenciesVersions (7)Used By (3)

carve-php
=========

[](#carve-php)

PHP parser and renderer for [Carve](https://github.com/markup-carve/carve), a post-Markdown lightweight markup language with visual mnemonics and human-centered design.

Implements **Carve spec 0.1** (see [Versioning &amp; Changelog](https://markup-carve.github.io/carve/versioning)).

Origins
-------

[](#origins)

Carve-PHP is a hard fork of [djot-php](https://github.com/php-collective/djot-php) by the PHP Collective. The fork preserves the architecture, AST, renderer pipeline, profiles, and extensions, and replaces Djot's syntax rules with Carve's. The MIT license carries over; copyright lines remain in `LICENSE`.

For the original Djot implementation, use [`php-collective/djot`](https://packagist.org/packages/php-collective/djot) instead.

Installation
------------

[](#installation)

```
composer require markup-carve/carve-php
```

Usage
-----

[](#usage)

```
use MarkupCarve\Carve\CarveConverter;

$converter = new CarveConverter();
$html = $converter->convert('# Hello /Carve/');
```

Besides HTML, the same AST renders to Markdown, plain text, and ANSI via the `CarveConverter::markdown()`, `::plainText()`, and `::ansi()` factories:

```
$markdown = CarveConverter::markdown()->convert('# Hello /Carve/');
$ansi = CarveConverter::ansi()->convert('# Hello /Carve/');
```

CLI
---

[](#cli)

The package ships a `bin/carve` executable that reads Carve from a file or stdin and writes the rendered output to stdout. HTML is the default; pass a format flag for another output:

```
bin/carve README.crv > README.html   # HTML (default)
bin/carve --markdown README.crv      # Markdown
bin/carve --plain README.crv         # plain text
bin/carve --ansi README.crv          # ANSI-colored terminal text
echo '# Hello' | bin/carve           # render from stdin
```

`--html` / `--markdown` (`--md`) / `--plain` (`--plain-text`) / `--ansi` select the format. `-o FILE` writes to a file; `-w`/`--warnings` and `--strict` report parse warnings (exit 1 under `--strict`); `-x`/`--xhtml` and `-s`/`--safe` apply to HTML output only. Run `bin/carve --help` for the full list.

Sandbox
-------

[](#sandbox)

Try this implementation live in the [Carve sandbox](https://sandbox.dereuromark.de/sandbox/carve) - explore syntax and extensions, inspect output, and share snippets via pastebin-style links. It also powers the [wp-carve](https://github.com/markup-carve/wp-carve) WordPress plugin.

Extension Matchers
------------------

[](#extension-matchers)

Carve-PHP supports parse-stage extension matchers alongside render hooks and document transforms. Matchers are tried only where core syntax declines, so core parsing always wins first.

```
use MarkupCarve\Carve\CarveConverter;
use MarkupCarve\Carve\Node\Inline\Text;
use MarkupCarve\Carve\Parser\MatcherContext;

$converter = new CarveConverter();

$converter->getParser()->getInlineParser()->addInlineMatcher(
    function (string $text, int $pos, MatcherContext $ctx): ?array {
        if (!preg_match('/\G\{\{([a-z]+)\}\}/', $text, $m, 0, $pos)) {
            return null;
        }

        return ['node' => new Text('VAR:' . $m[1]), 'end' => $pos + strlen($m[0])];
    },
    priority: 0,
    triggerChars: '{', // only run this matcher at a `{`
);
```

`MatcherContext` exposes definition tables (`getReference()`, `hasFootnote()`, `getAbbreviation()`) and recursive parse helpers (`parseInlines()`, `parseBlocks()`). Matchers run by descending `priority`, then registration order. `addInlinePattern()` and `addBlockPattern()` remain available as regex sugar over the same matcher contract.

For a raw-closure `addInlineMatcher()`, pass `triggerChars` (the literal first bytes the matcher can ever fire on, e.g. `'{'` above) so the parser only invokes it at those positions. Without it, the matcher runs at **every** scan position and disables the per-character fast path for the whole document — a measurable slowdown on long inputs. A matcher registered through `addInlinePattern()`derives its trigger bytes from the pattern automatically.

The normative extension contract lives in [`carve/docs/extensions.md`](https://github.com/markup-carve/carve/blob/main/docs/extensions.md). Extensions bundled with this package (such as `PlusBulletExtension`) are documented in [`docs/extensions.md`](docs/extensions.md).

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).

###  Health Score

29

—

LowBetter than 57% of packages

Maintenance61

Regular maintenance activity

Popularity20

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity18

Early-stage or recently created project

 Bus Factor1

Top contributor holds 99.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/39854?v=4)[Mark Scherer](/maintainers/dereuromark)[@dereuromark](https://github.com/dereuromark)

---

Top Contributors

[![dereuromark](https://avatars.githubusercontent.com/u/39854?v=4)](https://github.com/dereuromark "dereuromark (242 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

carvedjotmarkdownmarkupparserphp

### Embed Badge

![Health badge](/badges/markup-carve-carve-php/health.svg)

```
[![Health](https://phpackages.com/badges/markup-carve-carve-php/health.svg)](https://phpackages.com/packages/markup-carve-carve-php)
```

###  Alternatives

[sauladam/shipment-tracker

Parses tracking information for several carriers, like UPS, USPS, DHL and GLS by simply scraping the data. No need for any kind of API access.

9843.5k](/packages/sauladam-shipment-tracker)[jstewmc/rtf

Read and write Rich Text Format (RTF) documents with PHP

45153.1k6](/packages/jstewmc-rtf)[tcds-io/php-jackson

A lightweight, flexible object serializer for PHP, inspired by FasterXML/jackson

113.2k10](/packages/tcds-io-php-jackson)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
