php-collective/djot
PHP parser and renderer for Djot, the lightweight markup language created by CommonMark's author. Convert Djot markup to HTML through a clean, extensible API—a modern alternative to Markdown offering more consistent syntax, better footnotes, and richer built-in features.
Architecture fit
php-collective/djot is a pure-PHP, Composer-installable parser for Djot — a Markdown successor/alternative authored by John MacFarlane (pandoc/CommonMark lineage) that resolves Markdown's inline-parsing ambiguities and adds first-class attributes, footnotes, definition lists, math, and tables.DjotRenderer service, and a cached render() contract.MarkdownToDjot import (preserving references, entities, pointy destinations, link titles) and a Markdown output path, so Djot is no longer a one-way door; (b) extension surface — MentionsExtension now takes resolver / tagResolver closures plus a shared resolverContext, proving there is a real extension/hook model rather than a hardcoded renderer.Integration feasibility
composer require php-collective/djot), MIT-licensed, no framework coupling, no known transitive dependency weight. Expectation: PHP 8.x + ext-mbstring, PSR-4 autoloading.MarkdownToDjot.trustedRawHtml: true is passed — and resolved mention/tag URLs pass a URL-safety check.Technical risk
djot.js, not just internal expectations — a good sign. Parity with the upstream spec test suite remains the single most important thing to verify.@name must not become an SSRF/open-redirect vector.league/commonmark), adopting Djot splits the content toolchain, editor support, and contributor familiarity. 0.1.34's Markdown import/export meaningfully lowers this cost — it makes coexistence and reversibility credible — but does not eliminate it.Key questions
djot.js) parity tracked release-over-release?resolver, tagResolver, resolverContext)? Closures are a public surface we will write code against.MarkdownToDjot on our actual corpus, and is round-tripping (Markdown → Djot → Markdown) lossless enough to use as a migration and rollback tool?Stack fit
DjotRenderer singleton in a small package/service provider, expose a Djot::toHtml(string $markdown): string facade, a Blade::directive('djot') for inline content, and a Cast/accessor for Eloquent columns.rendered_html column or a cache key, never on every read. Rendering is a pure function of source + package version + path configuration, so cache keys must include both — 0.1.34 would otherwise leave stale HTML for every fenced block containing a blank line.MentionsExtension resolvers rather than post-processing HTML. This keeps link construction in our code (testable, URL-safe) instead of in string manipulation, and gives us one place to enforce internal-link policy.SanitizerInterface, applied by default, with an explicit opt-out reserved for trusted internal and trusted raw-HTML content (mirroring the package's own trustedRawHtml posture).Migration path
MarkdownToDjot is now the first tool to evaluate, not editorial rewriting. Run it over a sample of the real corpus, diff the rendered output against the existing CommonMark renderer, and quantify the delta before committing to any hand-migration.Compatibility
league/commonmark can coexist; both are standalone).Sequencing
MarkdownToDjot over real content, diff rendered output vs. current renderer, and validate the Markdown export round-trip as an exit ramp.Maintenance
djot.js as canonical; we should adopt the same stance.render() call: AST access, two rendering paths, extension resolvers, and Markdown import/export. Keep each behind a thin wrapper interface so a fork or replacement stays a contained change, but budget more integration surface than the 0.1.33-era assessment implied.resolverContext are new in 0.1.34 and have no stated stability guarantee.Support
@mention didn't resolve. Resolver failures need logging and a visible-but-safe fallback.Scaling
Failure modes
Ramp-up
How can I help you explore Laravel packages today?