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.
Comments
  • Question: How to add classes on specific node ?

    Question: How to add classes on specific node ?

    Question

    I have a common markdown content, without any specific attributes. When rendering markdown to HTML, I want to see some CSS Classes on HTML nodes.

    Let's say :

    • All H1 nodes : .title-main
    • All Table nodes : .table
    • All Table Row nodes : .table .table-row

    Is this possible without creating custom renderer ?

    It could be awesome to be able to configure using the environment :

    $config = [
      'html_classes' => [
        'h1' => '.title-main',
        'table' => '.table',
      ],
    ];
    

    The use case is : I'm using a bought theme that request some css class. I don't want to change markdown original content, and I don't want to change theme.

    Thank a lot for your awesome job on this package !

    Regards,

    enhancement question do not close 
    opened by armetiz 22
  • 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.

    question performance 
    opened by markhalliwell 18
  • [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.

    enhancement feedback wanted discussion 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
  • 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 up-for-grabs feedback wanted 
    opened by aleemb 13
  • RFC: Moving BacktickParser to a delimiter processor?

    RFC: Moving BacktickParser to a delimiter processor?

    Description I'm implementing a Jira ticket format parser as an InlineParserInterface. I think I'm in the ballpark, but I've stumbled with this: I can't apply the transformation if the ticket name is between backticks, and I think the reason is that backticks are implemented as InlineParserInterface too.

    If I'm understanding the docs, backticks would be ideally implemented as DelimiterProcessorInterface: image

    • Do you think it would be reasonable to allow transformations to happen inside backticks?
    • It would be a problem in terms of backwards compatibility?
    • I think I could try to make a PR. I'm still not familiar with this package internals, so I would do my best.

    Example

    test FOO-123 <!-- this will output 'test <a href="https://foo.atlassian.net/browse/FOO-123">FOO-123</a>' -->
    
    `test FOO-123` <!-- this will output '<pre>test FOO-123</pre>' -->
    

    Did this project help you today? Did it make you happy in any way?

    Of course. This is allowing me to do a cool view of our changelog for our non-programmer co-workers! I'm very thankful to have such control over the parsing, and I would love to contribute back if I can.

    enhancement 
    opened by devnix 12
  • Feature Request: Merge Attributes and Footnotes Extensions

    Feature Request: Merge Attributes and Footnotes Extensions

    Given that this project has now consolidated a ton of these rando extensions into itself, I think the last two remaining popular extensions should follow suit:

    • [x] https://github.com/webuni/commonmark-attributes-extension
    • [x] https://github.com/rezozero/commonmark-ext-footnotes

    x-ref: https://github.com/rezozero/commonmark-ext-footnotes/issues/7

    enhancement do not close implemented 
    opened by markhalliwell 12
  • Consider renaming the master branch

    Consider renaming the master branch

    Not that this really needs any explanation, but for posterity sake I suppose: https://www.zdnet.com/article/github-to-replace-master-with-alternative-term-to-avoid-slavery-references/

    implemented 
    opened by markhalliwell 11
  • Smart Punctuation is incorrect on RTL direction

    Smart Punctuation is incorrect on RTL direction

    Version(s) affected

    2.3

    Description

    In RTL languages the smart punctuation should be reversed so 'رہیں' generates ’رہیں‘ instead of the desired ‘رہیں’.

    It's possible to change up the config to reverse the open/close but language detection (especially for bilingual setups) would be very useful.

    opened by aleemb 1
  • [WIP]: move trim from parser to renderer

    [WIP]: move trim from parser to renderer

    There is a PHPCS bug that I don't understand what is wrong with it: "Incorrect annotations group."

    Locally there are still 4 PHPUnit tests which fail. But I am not sure if there is not a fundamental error in thinking there. Because in XML there is the flag "xml:space="preserve"". It could even be that the test needs to be rethought.

    This pull-request is just to give you the opportunity to think about my suggestion (https://github.com/thephpleague/commonmark/discussions/923) and see how I implemented it.

    opened by MrSpoocy 0
  • Switch from dependabot to Renovate

    Switch from dependabot to Renovate

    up-for-grabs good first issue do not close hacktoberfest 
    opened by colinodell 0
  • Config doesn't unexpectedly doesn't support option.

    Config doesn't unexpectedly doesn't support option.

    Version(s) affected

    2.3.5

    Description

    The GithubFlavoredMarkdownExtension includes multiple extensions including the DisallowedRawHtmlExtension extension.

    Whether the config array allows a 'disallowed_raw_html' entry depends on whether the DisallowedRawHtmlExtension was added directly, or via the GithubFlavoredMarkdownExtension

    I was expecting the config allowed to be the same, no matter how the extensions were added.

    How to reproduce

    The code below has a if (false) that allows switching between adding extensions individually or just adding the github extension.

    Mardown:

    ### Code of conduct
    
    Short version, any behaviour that prevents people from being able to use this site to do "useful" work is very likely to see someone suspended. 
    
    <hr/>
    
    Here is a brief summary of the Code of Conduct in musical form:
    
    <iframe width="560" height="315" src="https://www.youtube.com/embed/HivxFBB87-Y" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
    

    Code:

    <?php
    
    use League\CommonMark\Extension\Autolink\AutolinkExtension;
    use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
    use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
    use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
    use League\CommonMark\Extension\Table\TableExtension;
    use League\CommonMark\Extension\TaskList\TaskListExtension;
    use League\CommonMark\Environment\Environment;
    use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
    use League\CommonMark\Normalizer\SlugNormalizer;
    use League\CommonMark\MarkdownConverter;
    use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
    
            $config = [
                'heading_permalink' => [
                    'html_class' => 'heading-permalink',
                    'id_prefix' => 'user-content',
                    'insert' => 'after',
                    'title' => 'Permalink',
                    'symbol' => "\u{00A0}\u{00A0}🔗",
                ],
                'slug_normalizer' => [
                    // ... other options here ...
                    'instance' => new SlugNormalizer(),
                ],
                'html_input' => 'allow',
                'disallowed_raw_html' => [
                    'disallowed_tags' => [
                        'title', 'textarea', 'style', 'xmp',
                        //'iframe',
                        'noembed', 'noframes', 'script', 'plaintext'
                    ],
                ],
            ];
    
            $environment = new Environment($config);
            $environment->addExtension(new CommonMarkCoreExtension());
            $environment->addExtension(new HeadingPermalinkExtension());
    
            if (false) {
                // This works
                $environment->addExtension(new AutolinkExtension());
                $environment->addExtension(new DisallowedRawHtmlExtension());
                $environment->addExtension(new StrikethroughExtension());
                $environment->addExtension(new TableExtension());
                $environment->addExtension(new TaskListExtension());
            }
            else {
                // This errors "Unexpected item 'disallowed_raw_html'."
                $environment->addExtension(new GithubFlavoredMarkdownExtension());
            }
    
            $converter = new MarkdownConverter($environment);
    
            return $converter->convert($markdown)->getContent();
    

    Possible solution

    No response

    Additional context

    No response

    Did this project help you today? Did it make you happy in any way?

    Did it make you happy in any way?

    Actually a little of the opposite....from the code above:

            $converter = new MarkdownConverter($environment);
    
            return $converter->convert($markdown)->getContent();
    

    It would be better if the config was checked for being valid in the MarkdownConverter constructor, rather than when we get to the convert step.

    Though as this is a personal opinion, I don't think it would be appropriate for me to open an issue for it. But as you were asking about feelings....

    bug 
    opened by Danack 4
  • Re-evaluate dependencies

    Re-evaluate dependencies

    I really liked how v1 had no external dependencies. In v2 we opted to pull in some dependencies instead of reinventing the wheel. I think this was a good decision, but do we truly need everything in that dependency tree? Maybe yes, maybe no. Let's explore if it's reasonable to reduce that footprint in any ways that don't negatively impact users or maintainers. (We don't want to just remove things for the sake of removing things). This way involve some major-version-level changes to league/config as well.

    We'll either confirm that we have exactly what we want/need, or we'll find areas to make small improvements.

    do not close 
    opened by colinodell 0
Releases(2.3.5)
  • 2.3.5(Jul 29, 2022)

  • 2.3.4(Jul 17, 2022)

    Changed

    • Made a number of small tweaks to the embed extension's parsing behavior to fix #898:
      • Changed EmbedStartParser to always capture embed-like lines in container blocks, regardless of parent block type
      • Changed EmbedProcessor to also remove Embed blocks that aren't direct children of the Document
      • Increased the priority of EmbedProcessor to 1010

    Fixed

    • Fixed EmbedExtension not parsing embeds following a list block (#898)
    Source code(tar.gz)
    Source code(zip)
  • 2.3.3(Jun 7, 2022)

  • 2.3.2(Jun 3, 2022)

  • 2.2.5(Jun 3, 2022)

  • 2.3.1(May 14, 2022)

  • 2.2.4(May 14, 2022)

  • 2.3.0(Apr 7, 2022)

    Added

    • Added new EmbedExtension (#805)
    • Added DocumentRendererInterface as a replacement for the now-deprecated MarkdownRendererInterface

    Deprecated

    • Deprecated MarkdownRendererInterface; use DocumentRendererInterface instead
    Source code(tar.gz)
    Source code(zip)
  • 2.2.3(Feb 26, 2022)

  • 2.1.3(Feb 26, 2022)

  • 2.0.4(Feb 26, 2022)

  • 2.2.2(Feb 13, 2022)

  • 2.1.2(Feb 13, 2022)

  • 2.0.3(Feb 13, 2022)

  • 2.2.1(Jan 25, 2022)

  • 2.2.0(Jan 22, 2022)

    Added

    • Added new ConverterInterface
    • Added new MarkdownToXmlConverter class
    • Added new HtmlDecorator class which can wrap existing renderers with additional HTML tags
    • Added new table/wrap config to apply an optional wrapping/container element around a table (#780)

    Changed

    • HtmlElement contents can now consist of any Stringable, not just HtmlElement and string

    Deprecated

    • Deprecated MarkdownConverterInterface and its convertToHtml() method; use ConverterInterface and convert() instead
    Source code(tar.gz)
    Source code(zip)
  • 1.6.7(Jan 13, 2022)

    Changed

    • Added ReturnTypeWillChange attribute to prevent PHP 8.1 deprecation warnings (#785)
    • Coerced punctuation counts to integers to ensure floats are never used
    Source code(tar.gz)
    Source code(zip)
  • 2.1.1(Jan 2, 2022)

  • 2.1.0(Dec 5, 2021)

    Added

    • Added support for ext-yaml in FrontMatterExtension (#715)
    • Added support for symfony/yaml v6.0 in FrontMatterExtension (#739)
    • Added new heading_permalink/aria_hidden config option (#741)

    Fixed

    • Fixed PHP 8.1 deprecation warning (#759, #762)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Aug 14, 2021)

    Changed

    • Bumped minimum version of league/config to support PHP 8.1

    Fixed

    • Fixed ability to register block parsers that identify lines starting with letters (#706)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Jul 31, 2021)

    Fixed

    • Fixed nested autolinks (#689)
    • Fixed description lists being parsed incorrectly (#692)
    • Fixed Table of Contents not respecting Heading Permalink prefixes (#690)
    Source code(tar.gz)
    Source code(zip)
  • 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)

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
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 204 Sep 23, 2022
A super lightweight Markdown parser for PHP projects and applications.

A speedy Markdown parser for PHP applications. This is a super lightweight Markdown parser for PHP projects and applications. It has a rather verbose

Ryan Chandler 13 May 31, 2022
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 14.2k Sep 24, 2022
A simple regex-based Markdown parser in PHP

Slimdown A simple regex-based Markdown parser in PHP. Supports the following elements (and can be extended via Slimdown::add_rule()): Headers Links Bo

Aband*nthecar 14 Sep 5, 2022
Generate pseudo-static pages from markdown and HTML files for Flarum

Flarum Pages Generator This is not a Flarum extension. This package provides a Flarum extender that you can use in the local extend.php to define cust

Clark Winkelmann 7 Feb 21, 2022
Symfony 5 bundle to easily create dynamic subpages with Markdown. Useful for help sections and wikis.

MarkdownWikiBundle This bundle allows you to create rich subpages in a Symfony project using Markdown. Pages are stored in a file cache and sourced fr

Gigadrive UG 3 Apr 26, 2022
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.5k Sep 28, 2022
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 14 Sep 11, 2022
PHP Markdown Engine Support

PHP Markdown Version v1.x support all PHP version >=5.4 v2.x support all PHP version >=7.0 Cài đặt thư viện Thư viện này được cài đặt thông qua Compos

Hung Nguyen 3 Jul 1, 2022
Rendering markdown from PHP code

JBZoo / Markdown Installing composer require jbzoo/markdown Usage Rendering Table <?php declare(strict_types=1); use JBZoo\Markdown\Table; echo (new

JBZoo Toolbox 1 Dec 26, 2021
PHP Markdown & Extra

PHP Markdown & Extra An updated and stripped version of the original PHP Markdown by Michel Fortin. Works quite well with PSR-0 autoloaders and is Com

dflydev 173 Jan 18, 2022
PHP based Markdown documentation viewer

PHP based viewer for Markdown files, to view them with fenced code highlighting and navigation.

null 4 Sep 10, 2022
Easily add routes to your Laravel app by creating Markdown or Blade files

Laravel Pages This package lets you create pages using Markdown or Blade without having to worry about creating routes or controllers yourself. Essent

ARCHTECH 103 Sep 12, 2022
Render colored Markdown contents on console terminal

cli-markdown Render colored markdown contents on console terminal Preview run demo by php example/demo.php Features support auto render color on termi

PHPComLab 5 Jan 27, 2022
markdown wiki/blog

Kwiki markdown wiki/blog Usage Place your markdown files in the /wiki directory. Categories are directories and subcategories are subdirectories. If y

Ryan Winchester 77 May 29, 2022
Gruik ! An open-source markdown note-taking web app. [ABANDONED PROJECT]

What is Gruik ? It's a free & open-source note-taking service. A space where you can store notes, tutorials, code snippets... by writing them in markd

Adrien Pétremann 331 Aug 25, 2022
Docbook Tool for static documentation generation from Markdown files

Roave Docbook Tool Static HTML and PDF generator tool for generating documentation from Markdown files. Generates a deployable HTML file from Markdown

Roave, LLC 30 Aug 1, 2022
PHP Documentation system.

PHP Documentation system Simple but powerful Markdown docs. Features Search within Markdown files Customizable Twig templates (Note: default design is

Róbert Kelčák 1 Jun 8, 2022
Highly-extensible PHP Markdown parser which fully supports the CommonMark and GFM specs.

league/commonmark league/commonmark is a highly-extensible PHP Markdown parser created by Colin O'Dell which supports the full CommonMark spec and Git

The League of Extraordinary Packages 2.3k Sep 28, 2022
A super fast, highly extensible markdown parser for PHP

A super fast, highly extensible markdown parser for PHP What is this? A set of PHP classes, each representing a Markdown flavor, and a command line to

Carsten Brandt 983 Sep 15, 2022