Highly-extensible PHP Markdown parser which fully supports the CommonMark and GFM specs.

Overview

league/commonmark

Latest Version Total Downloads Software License Build Status Coverage Status Quality Score CII Best Practices

Sponsor development of this project

league/commonmark

league/commonmark is a highly-extensible PHP Markdown parser created by Colin O'Dell which supports the full CommonMark spec and Github-Flavored Markdown. It is based on the CommonMark JS reference implementation by John MacFarlane (@jgm).

📦 Installation & Basic Usage

This project requires PHP 7.2 or higher with the mbstring extension. To install it via Composer simply run:

$ composer require league/commonmark

The CommonMarkConverter class provides a simple wrapper for converting CommonMark to HTML:

use League\CommonMark\CommonMarkConverter;

$converter = new CommonMarkConverter([
    'html_input' => 'strip',
    'allow_unsafe_links' => false,
]);

echo $converter->convertToHtml('# Hello World!');

// <h1>Hello World!</h1>

Or if you want Github-Flavored Markdown, use the GithubFlavoredMarkdownConverter class instead:

use League\CommonMark\GithubFlavoredMarkdownConverter;

$converter = new GithubFlavoredMarkdownConverter([
    'html_input' => 'strip',
    'allow_unsafe_links' => false,
]);

echo $converter->convertToHtml('# Hello World!');

// <h1>Hello World!</h1>

Please note that only UTF-8 and ASCII encodings are supported. If your Markdown uses a different encoding please convert it to UTF-8 before running it through this library.

🔒 If you will be parsing untrusted input from users, please consider setting the html_input and allow_unsafe_links options per the example above. See https://commonmark.thephpleague.com/security/ for more details. If you also do choose to allow raw HTML input from untrusted users, considering using a library (like HTML Purifier) to provide additional HTML filtering.

📓 Documentation

Full documentation on advanced usage, configuration, and customization can be found at commonmark.thephpleague.com.

Upgrading

Information on how to upgrade to newer versions of this library can be found at https://commonmark.thephpleague.com/releases.

💻 Github-Flavored Markdown

The GithubFlavoredMarkdownConverter shown earlier is a drop-in replacement for the CommonMarkConverter which adds additional features found in the GFM spec:

  • Autolinks
  • Disallowed raw HTML
  • Strikethrough
  • Tables
  • Task Lists

See the Extensions documentation for more details on how to include only certain GFM features if you don't want them all.

🗃️ Related Packages

Integrations

Included Extensions

See our extension documentation for a full list of extensions bundled with this library.

Community Extensions

Custom parsers/renderers can be bundled into extensions which extend CommonMark. Here are some that you may find interesting:

Others can be found on Packagist under the commonmark-extension package type.

If you build your own, feel free to submit a PR to add it to this list!

Others

Check out the other cool things people are doing with league/commonmark: https://packagist.org/packages/league/commonmark/dependents

🏷️ Versioning

SemVer is followed closely. Minor and patch releases should not introduce breaking changes to the codebase; however, they might change the resulting AST or HTML output of parsed Markdown (due to bug fixes, spec changes, etc.) As a result, you might get slightly different HTML, but any custom code built onto this library should still function correctly.

Any classes or methods marked @internal are not intended for use outside of this library and are subject to breaking changes at any time, so please avoid using them.

🛠️ Maintenance & Support

When a new minor version (e.g. 1.4 -> 1.5) is released, the previous one (1.4) will continue to receive security and critical bug fixes for at least 3 months.

When a new major version is released (e.g. 1.5 -> 2.0), the previous one (1.5) will receive critical bug fixes for at least 3 months and security updates for 6 months after that new release comes out.

(This policy may change in the future and exceptions may be made on a case-by-case basis.)

Professional support, including notification of new releases and security updates, is available through a Tidelift Subscription.

👷‍♀️ Contributing

To report a security vulnerability, please use the Tidelift security contact. Tidelift will coordinate the fix and disclosure with us.

If you encounter a bug in the spec, please report it to the CommonMark project. Any resulting fix will eventually be implemented in this project as well.

Contributions to this library are welcome, especially ones that:

Major refactoring to core parsing logic should be avoided if possible so that we can easily follow updates made to the reference implementation. That being said, we will absolutely consider changes which don't deviate too far from the reference spec or which are favored by other popular CommonMark implementations.

Please see CONTRIBUTING for additional details.

🧪 Testing

$ composer test

This will also test league/commonmark against the latest supported spec.

🚀 Performance Benchmarks

You can compare the performance of league/commonmark to other popular parsers by running the included benchmark tool:

$ ./tests/benchmark/benchmark.php

👥 Credits & Acknowledgements

This code is partially based on the CommonMark JS reference implementation which is written, maintained and copyrighted by John MacFarlane. This project simply wouldn't exist without his work.

Sponsors

We'd also like to extend our sincere thanks the following sponsors who support ongoing development of this project:

Are you interested in sponsoring development of this project? See https://www.colinodell.com/sponsor for a list of ways to contribute.

📄 License

league/commonmark is licensed under the BSD-3 license. See the LICENSE file for more details.

🏛️ Governance

This project is primarily maintained by Colin O'Dell. Members of the PHP League Leadership Team may occasionally assist with some of these duties.

🗺️ Who Uses It?

This project is used by Drupal, Laravel Framework, Cachet, Firefly III, Neos, Daux.io, and more!


Get professional support for league/commonmark with a Tidelift subscription
Tidelift helps make open source sustainable for maintainers while giving companies
assurances about security, maintenance, and licensing for their dependencies.
Issues
  • WIP: Double-linked list based AST

    WIP: Double-linked list based AST

    • [x] Add base Node object which uses double-linked list
    • [x] Cleanup deprecated methods calls
    • [x] Add NodeWalker
    • [x] Simplify inline parsers
    • [x] Cleanup code

    This PR includes major refactoring of current commonmark implementation

    Changes

    • Double-linked list based AST
    • Simplified Delimiters and Inline parsers: instead of storing position, we now can store InlineNode.
    • Ability to modify AST in runtime by using NodeWalkers
    • AbstractInlineContainer replaced with InlineContainer interface

    NodeWalker

    NodeWalker can be used to change AST in runtime. Each node has walker method, which will create node walker for given node. Here is example of how to capitalize all emphasis in document:

    $doc = 'Hello *world*';
    
    $ast = $parser->parse($doc);
    $walker = $ast->walker();
    $inEmphasis = false;
    
    while (($event = $walker->next())) {
        $node = $event->getNode();
        if ($node instanceof Emphasis) {
            if ($event->isEntering()) {
                $inEmphasis = true;
            } else {
                $inEmphasis = false;
                // add Emphasis node's children as siblings
                while($node->firstChild()) {
                    $node->insertBefore($node->firstChild());
                }
                // remove the empty Emphasis node
                $node->detach();
            }
        } else if ($inEmphasis && $node instanceof Text) {
            $node->setContent(strtoupper($node->getContent()));
        }
    }
    
    $html = $renderer->renderBlock($ast); // <p>Hello WORLD</p>
    
    enhancement 
    opened by fesor 22
  • How do I add custom directives?

    How do I add custom directives?

    Given that @philsturgeon nearly wet his pants in excitement about this repo, I figured I'd check it out. I've been using cebe/markdown as a base parser - with extensions for leanpub's garbage - and while I'd like to switch to this, I haven't been able to figure out where I should hook into to add custom directives.

    Any thoughts on how I might go about this?

    opened by josegonzalez 21
  • PECL Extension

    PECL Extension

    So this is more of an open-ended question of sorts.

    Are there any plans for providing a PECL compatible extension of this project?

    It'd be nice to have the power/speed of https://github.com/commonmark/cmark that mimic this project's APIs.

    I've found https://github.com/krakjoe/cmark, but it seems to be a completely custom and standalone implementation.

    performance question 
    opened by markhalliwell 18
  • Image class attribute

    Image class attribute

    It should be possible to add a class to an image.

    opened by jbrooksuk 14
  • [2.0] Revise configuration approach

    [2.0] Revise configuration approach

    Our approach to configuration has a few shortcomings:

    • No support for providing default values, overriding them during MD->HTML conversion, and then rolling back before subsequent conversions
    • No support for validating types
    • Too many ways to set, get, and override configurations, some of which support /-delimited paths and others that don't
    • ConfigurationAwareInterface potentially allows people to pull configuration values out immediately instead of hanging onto the ConfigurationInterface object and lazily checking values later - the latter is recommended, but we don't document that anywhere.
    • It's basically a free-for-all

    The current approach works well enough for 1.x, but it's going to prevent some features like #442 being able to override configuration values (without causing weird side effects)

    I'd therefore like to revisit how we implement, handle, and document Configuration within this library for v2.

    discussion enhancement feedback wanted implemented 
    opened by colinodell 13
  • Add a new `html_input` option

    Add a new `html_input` option

    See #253, this is still WIP. That was easier than I thought, however I think it will require some more thinking. I'm pushing it "as-is" so that we can progress on what to do:

    • what name for the option controlling "allowing unsafe links"?
    • do the constants on the Environment class make sense to you?

    Feel free to send any other comment about the code, including small coding style stuff, I don't mind at all.

    The new html_input option allows 3 different behaviors:

    • strip HTML input
    • allow HTML input
    • escape HTML input
    opened by mnapoli 13
  • Add ability to configure characters and disable emphasis/strong

    Add ability to configure characters and disable emphasis/strong

    • [x] Option to disable parsing of _
    • [x] Option to disable parsing of *
    • [x] Option to disable rendering of emphasis
    • [x] Option to disable rendering of strong
    • [x] Tests

    Is this something you would be open to taking into core? If so, I'll write some tests for it. (Any suggestions for how the tests should be organized?)

    enhancement 
    opened by 0b10011 13
  • Added support for element visitors

    Added support for element visitors

    Todo:

    • [x] Finish implementation
    • [x] Add tests
    enhancement feedback wanted on hold 
    opened by hason 13
  • Support for multiple renderers

    Support for multiple renderers

    My use case is that I need custom renderers for images and depending on the image URL, these renders will render the image as an iframe for YouTube, Vimeo, etc. At present I use the Sundown renderer and I have stuffed all these renderers into one big file but would like to move over to this lib and cleanup the mess while I'm at it.

    I also imagine that a lot of contributors can then share their own YoutubeRenderer (or generic VideoRenderer). This would make extensibility a lot more fun and build an ecosystem around it. Maybe even give way to an extensions repo.

    Based on your suggestion in #32, I currently render my custom Renderer as

    $environment->addInlineRenderer('League\CommonMark\Inline\Element\Image', new MediaRenderer());
    

    However, this only allows attaching a single renderer. It would be nice if the renderer can work sort of like conventional event handlers with the possibility to either chain the output as input to other renderers or stop propagation. The easiest approach would be to have symmetric input/output for renderers that would make chaining a breeze. Currently the input/output is (AbstractInline, HtmlRenderer)/HtmlElement.

    enhancement feedback wanted up-for-grabs 
    opened by aleemb 13
  • Standardize delimiter processing node types

    Standardize delimiter processing node types

    This fixes a couple of type issues found in 1.0.0-beta1

    opened by colinodell 12
  • Fix autolinks being incorrectly nested inside of links

    Fix autolinks being incorrectly nested inside of links

    Fixes #689

    bug 
    opened by colinodell 0
  • Table of Contents links and Permalink IDs don't match

    Table of Contents links and Permalink IDs don't match

    Version(s) affected: 2.0.0

    Description
    When using HeadingPermalinkExtension along with TableOfContentsExtension links in the table of contents won't link to the corresponding Permalink

    How to reproduce

    use League\CommonMark\Environment\Environment;
    use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
    use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
    use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
    use League\CommonMark\MarkdownConverter;
    
    $environment = new Environment([]);
    $environment->addExtension(new CommonMarkCoreExtension());
    $environment->addExtension(new HeadingPermalinkExtension());
    $environment->addExtension(new TableOfContentsExtension());
    
    $converter = new MarkdownConverter($environment);
    
    echo $converter->convertToHtml("# Test");
    

    Produces

    <ul class="table-of-contents">
      <li>
        <a href="#test">Test</a>
      </li>
    </ul>
    <h1>
      <a id="content-test" href="#content-test" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>
      Test
    </h1>
    

    As you can see href="#test" doesn't match with id="content-test"

    bug 
    opened by onigoetz 4
  • AutolinkExtension parses emails twice

    AutolinkExtension parses emails twice

    Version(s) affected: 2.0.0

    Description
    Using CommonMarkCoreExtension and AutolinkExtension together with mail addresses results in nested links

    How to reproduce

    use League\CommonMark\MarkdownConverter;
    use League\CommonMark\Environment\Environment;
    use League\CommonMark\Extension\Autolink\AutolinkExtension;
    use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
    
    $environment = new Environment([]);
    $environment->addExtension(new CommonMarkCoreExtension());
    $environment->addExtension(new AutolinkExtension());
    
    $converter = new MarkdownConverter($environment);
    
    echo $converter->convertToHtml('[[email protected]](mailto:[email protected])');
    

    results in

    <p>
      <a href="mailto:[email protected]">
        <a href="mailto:[email protected]">
          [email protected]
        </a>
      </a>
    </p>
    

    But I would have expected (babelmark too) to get

    <p>
      <a href="mailto:[email protected]">
        [email protected]
      </a>
    </p>
    

    P.S. Congrats and great work on V2 ! I'm integrating it in Daux and it's going well so far :)

    bug 
    opened by onigoetz 1
  • Drop PHP 7.4 support

    Drop PHP 7.4 support

    We will drop PHP 7.4 support in our 3.0 release

    do not close 
    opened by colinodell 0
  • Optimize Cursor implementation

    Optimize Cursor implementation

    It may be possible to optimize the Cursor implementation by relying more heavily on byte positions internally than character positions. It's possible that character positions could be eliminated completely if they aren't entirely needed by external code, or perhaps we could track both for convenience but only rely on byte positions internally.

    do not close performance 
    opened by colinodell 0
  • Optimize regular expressions

    Optimize regular expressions

    Investigate whether the performance of regexes used in this library can be improved. Look for things like excessive backtracking. Use the debugger on https://regex101.com/ to help.

    do not close performance 
    opened by colinodell 0
  • Feature Request: Custom widget rendering using placeholder system

    Feature Request: Custom widget rendering using placeholder system

    Based on table of contents position=placeholder system, I want to be able to add custom "widget".

    Example:

    $environment = new CommonMark\Environment\Environment([
        'widgets' => [
            [
                'content' => '<span>This is an example</span>',
                'placeholder' => '[EXAMPLE]',
            ],
            [
                'content' => static function() {
                    return '<span>This is an other example</span>';
                },
                'placeholder' => '[EXAMPLE_BIS]',
            ],
        ],
    ]);
    

    Markdown content.

    Some content
    Some content
    [EXAMPLE]
    Some content
    [EXAMPLE_BIS]
    Some content
    [EXAMPLE]
    Some content
    Some content
    

    HTML

    <p>Some content</p>
    <p>Some content</p>
    <span>This is an example<span>
    <p>Some content</p>
    <span>This is an example<span>
    <p>Some content</p>
    <span>This is an other example<span>
    

    Regards.

    Thomas.

    enhancement not enough info 
    opened by armetiz 3
  • WIP: Emoji extension

    WIP: Emoji extension

    This is a WIP for #421, an emoji extension implementation using https://github.com/unicorn-fail/emoji

    ~~I haven't yet actually tried this to see if it works as expected, this work is based solely on IDE reliance on API implementation.~~

    This, currently, includes a single test as a POC

    do not close enhancement needs tests 
    opened by markhalliwell 6
  • TaskList: Listener to update markdown

    TaskList: Listener to update markdown

    I was wondering if commonmark provided example for TaskListExtension how to:

    1. add javascript listener on click of task item
    2. modify markdown to handle the ticked state of the task item

    this would make implementing full task list functionality easier for downstream projects.

    discussion do not close enhancement feedback wanted 
    opened by glensc 7
  • Feature Request: Emoji Parser

    Feature Request: Emoji Parser

    See https://github.com/thephpleague/commonmark-extras/issues/19

    do not close enhancement 
    opened by colinodell 10
Releases(2.0.0)
  • 2.0.0(Jul 24, 2021)

  • 2.0.0-rc2(Jul 17, 2021)

  • 1.6.6(Jul 17, 2021)

  • 2.0.0-rc1(Jul 10, 2021)

  • 2.0.0-beta3(Jul 3, 2021)

    Changed

    • Any leading UTF-8 BOM will be stripped from the input
    • The getEnvironment() method of CommonMarkConverter and GithubFlavoredMarkdownConverter will always return the concrete, configurable Environment for upgrading convenience
    • Optimized AST iteration
    • Lots of small micro-optimizations
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0-beta2(Jun 27, 2021)

    See https://commonmark.thephpleague.com/2.0/upgrading/ for detailed information on upgrading to version 2.0.

    Added

    • Added new Node::iterator() method and NodeIterator class for faster AST iteration (#683, #684)

    Changed

    • Made compatible with CommonMark spec 0.30.0
    • Optimized link label parsing
    • Optimized AST iteration for a 50% performance boost in some event listeners (#683, #684)

    Fixed

    • Fixed processing instructions with EOLs
    • Fixed case-insensitive matching for HTML tag types
    • Fixed type 7 HTML blocks incorrectly interrupting lazy paragraphs
    • Fixed newlines in reference labels not collapsing into spaces
    • Fixed link label normalization with escaped newlines
    • Fixed unnecessary AST iteration when no default attributes are configured
    Source code(tar.gz)
    Source code(zip)
  • 1.6.5(Jun 26, 2021)

    Changed

    • Simplified checks for thematic breaks

    Fixed

    • Fixed ExternalLinkProcessor not handling autolinks by adjusting its priority to -50 (#681)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0-beta1(Jun 20, 2021)

    See https://commonmark.thephpleague.com/2.0/upgrading/ for detailed information on upgrading to version 2.0.

    Added

    • Added three new extensions:
    • Added new XmlRenderer to simplify AST debugging (see documentation) (#431)
    • Added the ability to configure disallowed raw HTML tags (#507)
    • Added the ability for Mentions to use multiple characters for their symbol (#514, #550)
    • Added the ability to delegate event dispatching to PSR-14 compliant event dispatcher libraries
    • Added new configuration options:
      • Added heading_permalink/min_heading_level and heading_permalink/max_heading_level options to control which headings get permalinks (#519)
      • Added heading_permalink/fragment_prefix to allow customizing the URL fragment prefix (#602)
      • Added footnote/backref_symbol option for customizing backreference link appearance (#522)
      • Added slug_normalizer/max_length option to control the maximum length of generated URL slugs
      • Added slug_normalizer/unique option to control whether unique slugs should be generated per-document or per-environment
    • Added purity markers throughout the codebase (verified with Psalm)
    • Added Query class to simplify Node traversal when looking to take action on certain Nodes
    • Added new HtmlFilter and StringContainerHelper utility classes
    • Added new AbstractBlockContinueParser class to simplify the creation of custom block parsers
    • Added several new classes and interfaces:
      • BlockContinue
      • BlockContinueParserInterface
      • BlockContinueParserWithInlinesInterface
      • BlockStart
      • BlockStartParserInterface
      • ChildNodeRendererInterface
      • ConfigurableExtensionInterface
      • CursorState
      • DashParser (extracted from PunctuationParser)
      • DelimiterParser
      • DocumentBlockParser
      • DocumentPreRenderEvent
      • DocumentRenderedEvent
      • EllipsesParser (extracted from PunctuationParser)
      • ExpressionInterface
      • FallbackNodeXmlRenderer
      • InlineParserEngineInterface
      • InlineParserMatch
      • MarkdownParserState
      • MarkdownParserStateInterface
      • MarkdownRendererInterface
      • Query
      • RawMarkupContainerInterface
      • ReferenceableInterface
      • RenderedContent
      • RenderedContentInterface
      • ReplaceUnpairedQuotesListener
      • SpecReader
      • TableOfContentsRenderer
      • UniqueSlugNormalizer
      • UniqueSlugNormalizerInterface
      • XmlRenderer
      • XmlNodeRendererInterface
    • Added several new methods:
      • Cursor::getCurrentCharacter()
      • Environment::createDefaultConfiguration()
      • Environment::setEventDispatcher()
      • EnvironmentInterface::getExtensions()
      • EnvironmentInterface::getInlineParsers()
      • EnvironmentInterface::getSlugNormalizer()
      • FencedCode::setInfo()
      • Heading::setLevel()
      • HtmlRenderer::renderDocument()
      • InlineParserContext::getFullMatch()
      • InlineParserContext::getFullMatchLength()
      • InlineParserContext::getMatches()
      • InlineParserContext::getSubMatches()
      • LinkParserHelper::parsePartialLinkLabel()
      • LinkParserHelper::parsePartialLinkTitle()
      • Node::assertInstanceOf()
      • RegexHelper::isLetter()
      • StringContainerInterface::setLiteral()
      • TableCell::getType()
      • TableCell::setType()
      • TableCell::getAlign()
      • TableCell::setAlign()

    Changed

    • Changed the converter return type
      • CommonMarkConverter::convertToHtml() now returns an instance of RenderedContentInterface. This can be cast to a string for backward compatibility with 1.x.
    • Table of Contents items are no longer wrapped with <p> tags (#613)
    • Heading Permalinks now link to element IDs instead of using name attributes (#602)
    • Heading Permalink IDs and URL fragments now have a content prefix by default (#602)
    • Changes to configuration options:
      • enable_em has been renamed to commonmark/enable_em
      • enable_strong has been renamed to commonmark/enable_strong
      • use_asterisk has been renamed to commonmark/use_asterisk
      • use_underscore has been renamed to commonmark/use_underscore
      • unordered_list_markers has been renamed to commonmark/unordered_list_markers
      • mentions/*/symbol has been renamed to mentions/*/prefix
      • mentions/*/regex has been renamed to mentions/*/pattern and requires partial regular expressions (without delimiters or flags)
      • max_nesting_level now defaults to PHP_INT_MAX and no longer supports floats
      • heading_permalink/slug_normalizer has been renamed to slug_normalizer/instance
    • Event dispatching is now fully PSR-14 compliant
    • Moved and renamed several classes - see the full list here
    • The HeadingPermalinkExtension and FootnoteExtension were modified to ensure they never produce a slug which conflicts with slugs created by the other extension
    • SlugNormalizer::normalizer() now supports optional prefixes and max length options passed in via the $context argument
    • The AbstractBlock::$data and AbstractInline::$data arrays were replaced with a Data array-like object on the base Node class
    • Implemented a new approach to block parsing. This was a massive change, so here are the highlights:
      • Functionality previously found in block parsers and node elements has moved to block parser factories and block parsers, respectively (more details)
      • ConfigurableEnvironmentInterface::addBlockParser() is now EnvironmentBuilderInterface::addBlockParserFactory()
      • ReferenceParser was re-implemented and works completely different than before
      • The paragraph parser no longer needs to be added manually to the environment
    • Implemented a new approach to inline parsing where parsers can now specify longer strings or regular expressions they want to parse (instead of just single characters):
      • InlineParserInterface::getCharacters() is now getMatchDefinition() and returns an instance of InlineParserMatch
      • InlineParserContext::__construct() now requires the contents to be provided as a Cursor instead of a string
    • Implemented delimiter parsing as a special type of inline parser (via the new DelimiterParser class)
    • Changed block and inline rendering to use common methods and interfaces
      • BlockRendererInterface and InlineRendererInterface were replaced by NodeRendererInterface with slightly different parameters. All core renderers now implement this interface.
      • ConfigurableEnvironmentInterface::addBlockRenderer() and addInlineRenderer() were combined into EnvironmentBuilderInterface::addRenderer()
      • EnvironmentInterface::getBlockRenderersForClass() and getInlineRenderersForClass() are now just getRenderersForClass()
    • Completely refactored the Configuration implementation
      • All configuration-specific classes have been moved into a new league/config package with a new namespace
      • Configuration objects must now be configured with a schema and all options must match that schema - arbitrary keys are no longer permitted
      • Configuration::__construct() no longer accepts the default configuration values - use Configuration::merge() instead
      • ConfigurationInterface now only contains a get(string $key); this method no longer allows arbitrary default values to be returned if the option is missing
      • ConfigurableEnvironmentInterface was renamed to EnvironmentBuilderInterface
      • ExtensionInterface::register() now requires an EnvironmentBuilderInterface param instead of ConfigurableEnvironmentInterface
    • Added missing return types to virtually every class and interface method
    • Re-implemented the GFM Autolink extension using the new inline parser approach instead of document processors
      • EmailAutolinkProcessor is now EmailAutolinkParser
      • UrlAutolinkProcessor is now UrlAutolinkParser
    • HtmlElement can now properly handle array (i.e. class) and boolean (i.e. checked) attribute values
    • HtmlElement automatically flattens any attributes with array values into space-separated strings, removing duplicate entries
    • Combined separate classes/interfaces into one:
      • DisallowedRawHtmlRenderer replaces DisallowedRawHtmlBlockRenderer and DisallowedRawHtmlInlineRenderer
      • NodeRendererInterface replaces BlockRendererInterface and InlineRendererInterface
    • Renamed the following methods:
      • Environment and ConfigurableEnvironmentInterface:
        • addBlockParser() is now addBlockStartParser()
      • ReferenceMap and ReferenceMapInterface:
        • addReference() is now add()
        • getReference() is now get()
        • listReferences() is now getIterator()
      • Various node (block/inline) classes:
        • getContent() is now getLiteral()
        • setContent() is now setLiteral()
    • Moved and renamed the following constants:
      • EnvironmentInterface::HTML_INPUT_ALLOW is now HtmlFilter::ALLOW
      • EnvironmentInterface::HTML_INPUT_ESCAPE is now HtmlFilter::ESCAPE
      • EnvironmentInterface::HTML_INPUT_STRIP is now HtmlFilter::STRIP
      • TableCell::TYPE_HEAD is now TableCell::TYPE_HEADER
      • TableCell::TYPE_BODY is now TableCell::TYPE_DATA
    • Changed the visibility of the following properties:
      • AttributesInline::$attributes is now private
      • AttributesInline::$block is now private
      • TableCell::$align is now private
      • TableCell::$type is now private
      • TableSection::$type is now private
    • Several methods which previously returned $this now return void
      • Delimiter::setPrevious()
      • Node::replaceChildren()
      • Context::setTip()
      • Context::setContainer()
      • Context::setBlocksParsed()
      • AbstractStringContainer::setContent()
      • AbstractWebResource::setUrl()
    • Several classes are now marked final:
      • ArrayCollection
      • Emphasis
      • FencedCode
      • Heading
      • HtmlBlock
      • HtmlElement
      • HtmlInline
      • IndentedCode
      • Newline
      • Strikethrough
      • Strong
      • Text
    • Heading nodes no longer directly contain a copy of their inner text
    • StringContainerInterface can now be used for inlines, not just blocks
    • ArrayCollection only supports integer keys
    • HtmlElement now implements Stringable
    • Cursor::saveState() and Cursor::restoreState() now use CursorState objects instead of arrays
    • NodeWalker::next() now enters, traverses any children, and leaves all elements which may have children (basically all blocks plus any inlines with children). Previously, it only did this for elements explicitly marked as "containers".
    • InvalidOptionException was removed
    • Anything with a getReference(): ReferenceInterface method now implements ReferencableInterface
    • The SmartPunct extension now replaces all unpaired Quote elements with Text elements towards the end of parsing, making the QuoteRenderer unnecessary
    • Several changes made to the Footnote extension:
      • Footnote identifiers can no longer contain spaces
      • Anonymous footnotes can now span subsequent lines
      • Footnotes can now contain multiple lines of content, including sub-blocks, by indenting them
      • Footnote event listeners now have numbered priorities (but still execute in the same order)
      • Footnotes must now be separated from previous content by a blank line
    • The line numbers (keys) returned via MarkdownInput::getLines() now start at 1 instead of 0
    • DelimiterProcessorCollectionInterface now extends Countable
    • RegexHelper::PARTIAL_ constants must always be used in case-insensitive contexts
    • HeadingPermalinkProcessor no longer accepts text normalizers via the constructor - these must be provided via configuration instead
    • Blocks which can't contain inlines will no longer be asked to render inlines
    • AnonymousFootnoteRefParser and HeadingPermalinkProcessor now implement EnvironmentAwareInterface instead of ConfigurationAwareInterface
    • The second argument to TextNormalizerInterface::normalize() must now be an array
    • The title attribute for Link and Image nodes is now stored using a dedicated property instead of stashing it in $data
    • ListData::$delimiter now returns either ListBlock::DELIM_PERIOD or ListBlock::DELIM_PAREN instead of the literal delimiter

    Fixed

    • Fixed parsing of footnotes without content
    • Fixed rendering of orphaned footnotes and footnote refs
    • Fixed some URL autolinks breaking too early (#492)
    • Fixed AbstractStringContainer not actually being abstract

    Removed

    • Removed support for PHP 7.1, 7.2, and 7.3 (#625, #671)
    • Removed all previously-deprecated functionality:
      • Removed the ability to pass custom Environment instances into the CommonMarkConverter and GithubFlavoredMarkdownConverter constructors
      • Removed the Converter class and ConverterInterface
      • Removed the bin/commonmark script
      • Removed the Html5Entities utility class
      • Removed the InlineMentionParser (use MentionParser instead)
      • Removed DefaultSlugGenerator and SlugGeneratorInterface from the Extension/HeadingPermalink/Slug sub-namespace (use the new ones under ./SlugGenerator instead)
      • Removed the following ArrayCollection methods:
        • add()
        • set()
        • get()
        • remove()
        • isEmpty()
        • contains()
        • indexOf()
        • containsKey()
        • replaceWith()
        • removeGaps()
      • Removed the ConfigurableEnvironmentInterface::setConfig() method
      • Removed the ListBlock::TYPE_UNORDERED constant
      • Removed the CommonMarkConverter::VERSION constant
      • Removed the HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant
      • Removed the heading_permalink/inner_contents configuration option
    • Removed now-unused classes:
      • AbstractStringContainerBlock
      • BlockRendererInterface
      • Context
      • ContextInterface
      • Converter
      • ConverterInterface
      • InlineRendererInterface
      • PunctuationParser (was split into two classes: DashParser and EllipsesParser)
      • QuoteRenderer
      • UnmatchedBlockCloser
    • Removed the following methods, properties, and constants:
      • AbstractBlock::$open
      • AbstractBlock::$lastLineBlank
      • AbstractBlock::isContainer()
      • AbstractBlock::canContain()
      • AbstractBlock::isCode()
      • AbstractBlock::matchesNextLine()
      • AbstractBlock::endsWithBlankLine()
      • AbstractBlock::setLastLineBlank()
      • AbstractBlock::shouldLastLineBeBlank()
      • AbstractBlock::isOpen()
      • AbstractBlock::finalize()
      • AbstractBlock::getData()
      • AbstractInline::getData()
      • ConfigurableEnvironmentInterface::addBlockParser()
      • ConfigurableEnvironmentInterface::mergeConfig()
      • Delimiter::setCanClose()
      • EnvironmentInterface::getConfig()
      • EnvironmentInterface::getInlineParsersForCharacter()
      • EnvironmentInterface::getInlineParserCharacterRegex()
      • HtmlRenderer::renderBlock()
      • HtmlRenderer::renderBlocks()
      • HtmlRenderer::renderInline()
      • HtmlRenderer::renderInlines()
      • Node::isContainer()
      • RegexHelper::matchAll() (use the new matchFirst() method instead)
      • RegexHelper::REGEX_WHITESPACE
    • Removed the second $contents argument from the Heading constructor

    Deprecated

    The following things have been deprecated and will not be supported in v3.0:

    • Environment::mergeConfig() (set configuration before instantiation instead)
    • Environment::createCommonMarkEnvironment() and Environment::createGFMEnvironment()
      • Alternative 1: Use CommonMarkConverter or GithubFlavoredMarkdownConverter if you don't need to customize the environment
      • Alternative 2: Instantiate a new Environment and add the necessary extensions yourself
    Source code(tar.gz)
    Source code(zip)
  • 1.6.4(Jun 19, 2021)

  • 1.6.3(Jun 19, 2021)

  • 1.6.2(May 12, 2021)

  • 1.6.1(May 8, 2021)

  • 1.6.0(May 1, 2021)

    Please see https://commonmark.thephpleague.com/1.6/upgrading/ for important information about this release and the upcoming 2.0.0 version.

    Added

    • Added forward-compatibility for configuration options which will be changing in 2.0:
      • commonmark/enable_em (currently enable_em in 1.x)
      • commonmark/enable_strong (currently enable_strong in 1.x)
      • commonmark/use_asterisk (currently use_asterisk in 1.x)
      • commonmark/use_underscore (currently use_underscore in 1.x)
      • commonmark/unordered_list_markers (currently unordered_list_markers in 1.x)
      • mentions/*/prefix (currently mentions/*/symbol in 1.x)
      • mentions/*/pattern (currently mentions/*/regex in 1.x)
      • max_nesting_level (currently supports int and float values in 1.x; will only support int in 2.0)
    • Added new MarkdownConverter class for creating converters with custom environments; this replaces the previously-deprecated Converter class
    • Added new RegexHelper::matchFirst() method
    • Added new Configuration::exists() method

    Changed

    • The max_nesting_level option now defaults to PHP_INT_MAX instead of INF

    Deprecated

    • Deprecated the configuration options shown above
    • Deprecated the ability to pass a custom Environment into the constructors of CommonMarkConverter and GithubFlavoredMarkdownConverter; use MarkdownConverter instead
    • Deprecated ConfigurableEnvironmentInterface::setConfig(); use mergeConfig() instead
    • Deprecated calling ConfigurableEnvironmentInterface::mergeConfig() without any parameters
    • Deprecated calling Configuration::get() and EnvironmentInterface::getConfig() without any parameters
    • Deprecated calling Configuration::set() without the second $value parameter
    • Deprecated RegexHelper::matchAll(); use RegexHelper::matchFirst() instead
    • Deprecated extending the ArrayCollection class; will be marked final in 2.0

    Fixed

    • Fixed missing check for empty arrays being passed into the unordered_list_markers configuration option
    Source code(tar.gz)
    Source code(zip)
  • 1.5.8(Mar 28, 2021)

  • 1.5.7(Oct 31, 2020)

  • 1.5.6(Oct 17, 2020)

    Changed

    • Blocks added outside of the parsing context now have their start/end line numbers defaulted to 0 to avoid type errors (#579)

    Fixed

    • Fixed replacement blocks not inheriting the start line number of the container they're replacing (#579)
    • Fixed Table of Contents blocks not having correct start/end line numbers (#579)
    Source code(tar.gz)
    Source code(zip)
  • 1.5.5(Sep 13, 2020)

    Changed

    • Bumped CommonMark spec compliance to 0.28.2

    Fixed

    • Fixed textarea elements not being treated as a type 1 HTML block (like script, style, or pre)
    • Fixed autolink processor not handling other unmatched trailing parentheses
    Source code(tar.gz)
    Source code(zip)
  • 1.5.4(Aug 17, 2020)

  • 1.5.3(Jul 19, 2020)

  • 1.5.2(Jul 19, 2020)

    Changed

    • Significantly improved performance of the inline parser regex

    Fixed

    • Fixed parent class lookups for non-existent classes on PHP 8 (#517)
    Source code(tar.gz)
    Source code(zip)
  • 1.5.1(Jun 27, 2020)

  • 1.5.0(Jun 21, 2020)

    Added

    • Added new AttributesExtension based on https://github.com/webuni/commonmark-attributes-extension (#474)
    • Added new FootnoteExtension based on https://github.com/rezozero/commonmark-ext-footnotes (#474)
    • Added new MentionExtension to replace InlineMentionParser with more flexibility and customization
    • Added the ability to render TableOfContents nodes anywhere in a document (given by a placeholder)
    • Added the ability to properly clone Node objects
    • Added options to customize the value of rel attributes set via the ExternalLink extension (#476)
    • Added a new heading_permalink/slug_normalizer configuration option to allow custom slug generation (#460)
    • Added a new heading_permalink/symbol configuration option to replace the now deprecated heading_permalink/inner_contents configuration option (#505)
    • Added SlugNormalizer and TextNormalizer classes to make normalization reusable by extensions (#485)
    • Added new classes:
      • TableOfContentsGenerator
      • TableOfContentsGeneratorInterface
      • TableOfContentsPlaceholder
      • TableOfContentsPlaceholderParser
      • TableOfContentsPlaceholderRenderer

    Changed

    • "Moved" the TableOfContents class into a new Node sub-namespace (with backward-compatibility)
    • Reference labels are now generated and stored in lower-case instead of upper-case
    • Reference labels are no longer normalized inside the Reference, only the ReferenceMap

    Fixed

    • Fixed reference label case folding polyfill not being consistent between different PHP versions

    Deprecated

    • Deprecated the CommonMarkConverter::VERSION constant (#496)
    • Deprecated League\CommonMark\Extension\Autolink\InlineMentionParser (use League\CommonMark\Extension\Mention\MentionParser instead)
    • Deprecated everything under League\CommonMark\Extension\HeadingPermalink\Slug (use the classes under League\CommonMark\Normalizer instead)
    • Deprecated League\CommonMark\Extension\TableOfContents\TableOfContents (use the one in the new Node sub-namespace instead)
    • Deprecated the STYLE_ and NORMALIZE_ constants in TableOfContentsBuilder (use the ones in TableOfContentsGenerator instead)
    • Deprecated the \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant (#505)
    • Deprecated the heading_permalink/inner_contents configuration option in the HeadingPermalink extension (use the new heading_permalink/symbol configuration option instead) (#505)
    Source code(tar.gz)
    Source code(zip)
  • 1.4.3(May 4, 2020)

  • 1.4.2(Apr 24, 2020)

  • 1.4.1(Apr 20, 2020)

  • 1.4.0(Apr 18, 2020)

    Added

    • Added new Heading Permalink extension (#420)
    • Added new Table of Contents extension (#441)
    • Added new MarkdownConverterInterface as a long-term replacement for ConverterInterface (#439)
    • Added new DocumentPreParsedEvent event (#427, #359, #399)
    • Added new ListBlock::TYPE_BULLET constant as a replacement for ListBlock::TYPE_UNORDERED
    • Added new MarkdownInput class and MarkdownInputInterface to handle pre-parsing and allow listeners to replace Markdown contents

    Changed

    • Block & inline renderers will now render child classes automatically (#222, #209)
    • The ListBlock constants now use fully-lowercased values instead of titlecased values
    • Significantly improved typing

    Fixed

    • Fixed loose comparison when checking for table alignment
    • Fixed StaggeredDelimiterProcessor returning from a void function

    Deprecated

    • The Converter class has been deprecated; use CommonMarkConverter instead (#438, #439)
    • The ConverterInterface has been deprecated; use MarkdownConverterInterface instead (#438, #439)
    • The bin/commonmark script has been deprecated
    • The following methods of ArrayCollection have been deprecated:
      • add()
      • set()
      • get()
      • remove()
      • isEmpty()
      • contains()
      • indexOf()
      • containsKey()
      • replaceWith()
      • removeGaps()
    • The ListBlock::TYPE_UNORDERED constant has been deprecated, use ListBlock::TYPE_BULLET instead
    Source code(tar.gz)
    Source code(zip)
  • 1.3.4(Apr 13, 2020)

    Fixed

    • Fixed configuration/environment not being injected into event listeners when adding them via [$instance, 'method'] callable syntax (#440)
    Source code(tar.gz)
    Source code(zip)
  • 1.3.3(Apr 5, 2020)

    Fixed

    • Fixed event listeners not having the environment or configuration injected if they implemented the EnvironmentAwareInterface or ConfigurationAwareInterface (#423)
    Source code(tar.gz)
    Source code(zip)
  • 1.3.2(Mar 25, 2020)

  • 1.3.1(Feb 28, 2020)

Owner
The League of Extraordinary Packages
A group of developers who have banded together to build solid, well tested PHP packages using modern coding standards.
The League of Extraordinary Packages
Convert HTML to Markdown with PHP

HTML To Markdown for PHP Library which converts HTML to Markdown for your sanity and convenience. Requires: PHP 7.2+ Lead Developer: @colinodell Origi

The League of Extraordinary Packages 1.4k Jul 26, 2021
Parser for Markdown and Markdown Extra derived from the original Markdown.pl by John Gruber.

PHP Markdown PHP Markdown Lib 1.9.0 - 1 Dec 2019 by Michel Fortin https://michelf.ca/ based on Markdown by John Gruber https://daringfireball.net/ Int

Michel Fortin 3.2k Jul 24, 2021
A highly configurable markdown renderer and Blade component for Laravel

A highly configurable markdown renderer and Blade component for Laravel This package contains: a Blade component that can render markdown a highly con

Spatie 108 Jul 23, 2021
Better Markdown Parser in PHP

Parsedown Better Markdown Parser in PHP - Demo. Features One File No Dependencies Super Fast Extensible GitHub flavored Tested in 5.3 to 7.3 Markdown

Emanuil Rusev 13.8k Jul 29, 2021
一个结构清晰的,易于维护的,现代的PHP Markdown解析器

为何要写这样一个解析器 Markdown已经面世许多年了,国内外许多大大小小的网站都在用它,但是它的解析器却依然混乱不堪。SegmentFault 是中国较大规模使用 Markdown 语法的网站,我们一直在使用一些开源类库,包括但不限于 php-markdown CommonMark for PH

SegmentFault 思否 1.2k Jul 20, 2021
A PHP tool to generate templateable markdown documentation from the docblocks or type-hints of your codebase.

Roster Installation To install, simply require the package using composer: composer require

Jordan LeDoux 13 Jul 21, 2021