diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/0.20/basic-usage/index.html b/0.20/basic-usage/index.html new file mode 100644 index 0000000000..1b0eac0643 --- /dev/null +++ b/0.20/basic-usage/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/changelog/index.html b/0.20/changelog/index.html new file mode 100644 index 0000000000..08fe0717b9 --- /dev/null +++ b/0.20/changelog/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/command-line/index.html b/0.20/command-line/index.html new file mode 100644 index 0000000000..63fb4aa98c --- /dev/null +++ b/0.20/command-line/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/configuration/index.html b/0.20/configuration/index.html new file mode 100644 index 0000000000..70628e37c3 --- /dev/null +++ b/0.20/configuration/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/abstract-syntax-tree/index.html b/0.20/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..8afa76d6b2 --- /dev/null +++ b/0.20/customization/abstract-syntax-tree/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/block-parsing/index.html b/0.20/customization/block-parsing/index.html new file mode 100644 index 0000000000..f016e0f92a --- /dev/null +++ b/0.20/customization/block-parsing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/block-rendering/index.html b/0.20/customization/block-rendering/index.html new file mode 100644 index 0000000000..f9755a4fb4 --- /dev/null +++ b/0.20/customization/block-rendering/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/cursor/index.html b/0.20/customization/cursor/index.html new file mode 100644 index 0000000000..2713501fbf --- /dev/null +++ b/0.20/customization/cursor/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/delimiter-processing/index.html b/0.20/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..e80043d812 --- /dev/null +++ b/0.20/customization/delimiter-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/document-processing/index.html b/0.20/customization/document-processing/index.html new file mode 100644 index 0000000000..334f85ffb5 --- /dev/null +++ b/0.20/customization/document-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/environment/index.html b/0.20/customization/environment/index.html new file mode 100644 index 0000000000..2868ae7b3e --- /dev/null +++ b/0.20/customization/environment/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/extensions/index.html b/0.20/customization/extensions/index.html new file mode 100644 index 0000000000..eebdb10549 --- /dev/null +++ b/0.20/customization/extensions/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/index.html b/0.20/customization/index.html new file mode 100644 index 0000000000..92d0f965cb --- /dev/null +++ b/0.20/customization/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/inline-parsing/index.html b/0.20/customization/inline-parsing/index.html new file mode 100644 index 0000000000..9e584ae5d4 --- /dev/null +++ b/0.20/customization/inline-parsing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/inline-rendering/index.html b/0.20/customization/inline-rendering/index.html new file mode 100644 index 0000000000..2875af878e --- /dev/null +++ b/0.20/customization/inline-rendering/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/customization/overview/index.html b/0.20/customization/overview/index.html new file mode 100644 index 0000000000..92d0f965cb --- /dev/null +++ b/0.20/customization/overview/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/index.html b/0.20/index.html new file mode 100644 index 0000000000..b8380bb675 --- /dev/null +++ b/0.20/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/installation/index.html b/0.20/installation/index.html new file mode 100644 index 0000000000..b89d4a47a0 --- /dev/null +++ b/0.20/installation/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/security/index.html b/0.20/security/index.html new file mode 100644 index 0000000000..0d10b187cc --- /dev/null +++ b/0.20/security/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/0.20/upgrading/index.html b/0.20/upgrading/index.html new file mode 100644 index 0000000000..2419209b40 --- /dev/null +++ b/0.20/upgrading/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/1.0/basic-usage/index.html b/1.0/basic-usage/index.html new file mode 100644 index 0000000000..a66a98a2af --- /dev/null +++ b/1.0/basic-usage/index.html @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

The actual conversion process has three steps:

+ +
    +
  1. Creating an Environment, adding whichever extensions/parser/renders you need
  2. +
  3. Parsing the Markdown input into an AST
  4. +
  5. Rendering the AST document as HTML
  6. +
+ +

CommonMarkConverter handles this for you, but you can execute that process yourself if you wish:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+// <h1>Hello World!</h1>
+
+ +

Additional customization is also possible.

+ +

Supported Character Encodings

+ +

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.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/changelog/index.html b/1.0/changelog/index.html new file mode 100644 index 0000000000..898454d3bc --- /dev/null +++ b/1.0/changelog/index.html @@ -0,0 +1,623 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 1.0 - 1.2 releases are shown below. See the full list of releases for the complete changelog.

+ +

1.2.2 - 2020-01-16

+ +

This release contains the same changes as 1.1.3:

+ +

Fixed

+ + + +

1.1.3 - 2020-01-16

+ +

Fixed

+ + + +

1.2.1 - 2020-01-15

+ +

Changed

+ + + +

1.2.0 - 2020-01-09

+ +

Changed

+ + + +

1.1.2 - 2019-12-10

+ +

Fixed

+ + + +

1.1.1 - 2019-11-11

+ +

Fixed

+ + + +

1.1.0 - 2019-10-31

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.0.0 - 2019-06-29

+ +

First stable release! 🎉

+ +

No code changes have been introduced since 1.0.0-rc1

+ +

1.0.0-rc1 - 2019-06-20

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

1.0.0-beta4 - 2019-06-05

+ +

Added

+ + + +

Removed

+ + + +

1.0.0-beta3 - 2019-05-28

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta2 - 2019-05-27

+ +

This beta release fixes a couple of items that were not addressed in the previous beta.

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta1 - 2019-05-26

+ +

See the upgrading guide for additional information.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

Removed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/command-line/index.html b/1.0/command-line/index.html new file mode 100644 index 0000000000..e2edd43c60 --- /dev/null +++ b/1.0/command-line/index.html @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + Command Line - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Command Line

+ +

Markdown can be converted at the command line using the ./bin/commonmark script.

+ +

Usage

+ +
./bin/commonmark [OPTIONS] [FILE]
+
+ + + +

If no file is given, input will be read from STDIN.

+ +

Output will be written to STDOUT.

+ +

Examples

+ +

Converting a file named document.md

+ +
./bin/commonmark document.md
+
+ +

Converting a file and saving its output

+ +
./bin/commonmark document.md > output.html
+
+ +

Converting from STDIN

+ +
echo -e '# Hello World!' | ./bin/commonmark
+
+ +

Converting from STDIN and saving the output

+ +
echo -e '# Hello World!' | ./bin/commonmark > output.html
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/configuration/index.html b/1.0/configuration/index.html new file mode 100644 index 0000000000..21e1198a45 --- /dev/null +++ b/1.0/configuration/index.html @@ -0,0 +1,385 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

You can provide an array of configuration options to the CommonMarkConverter when creating it:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter([
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'enable_em' => true,
+    'enable_strong' => true,
+    'use_asterisk' => true,
+    'use_underscore' => true,
+    'unordered_list_markers' => ['-', '*', '+'],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => INF,
+]);
+
+ +

Here’s a list of currently-supported options:

+ + + +

Additional configuration options are available for some of the available extensions - refer to their individual documentation for more details.

+ +

The following options have been deprecated. They will no longer work once 1.0.0 is released:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

The Environment also exposes three methods for managing the configuration:

+ + + +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/abstract-syntax-tree/index.html b/1.0/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..8c2bd99429 --- /dev/null +++ b/1.0/customization/abstract-syntax-tree/index.html @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Traversal

+ +

The following methods can be used to traverse the AST:

+ + + +

Iteration / Walking the Tree

+ +

If you’d like to iterate through all the nodes, use the walker() method to obtain an instance of NodeWalker. This will walk through the entire tree, emitting NodeWalkerEvents along the way.

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'I am ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

This walker doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes.

+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/block-parsing/index.html b/1.0/customization/block-parsing/index.html new file mode 100644 index 0000000000..f1062de274 --- /dev/null +++ b/1.0/customization/block-parsing/index.html @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

Block parsers should implement BlockParserInterface and implement the following method:

+ +

parse()

+ +
public function parse(ContextInterface $context, Cursor $cursor): bool;
+
+ +

When parsing a new line, the DocParser iterates through all registered block parsers and calls their parse() method. Each parser must determine whether it can handle the given line; if so, it should parse the given block and return true.

+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the line will be parsed as text.

+ +

Returning true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of syntax indicating the block start
  2. +
  3. Add the parsed block via $context->addBlock()
  4. +
+ +

Tips

+ + + +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

Block elements also play a role during the parsing process as they tell the underlying engine how to handle subsequent blocks that are found.

+ +

AbstractBlockElement Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
canContain(...)Tell the engine whether a subsequent block can be added as a child of yours
isCode()Returns whether this block represents an extra-greedy <code> block
matchesNextLine(...)Returns whether this block continues onto the next line (some blocks are multi-line)
shouldLastLineBeBlank()Returns whether the last line should be blank (primarily used by ListItem elements)
finalize(...)Finalizes the block after all child items have been added, thus marking it as closed for modification
+ +

For examples on how these methods are used, see the core block element classes included with this library.

+ +

AbstractStringContainerBlock

+ +

If your element can contain strings of text, you should extend AbstractStringContainerBlock instead of AbstractBlock. This provides some additional methods needed to manage that inner text:

+ + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
handleRemainingContents(...)This is called when a block has been created but some other text still exists on that line
addLine(...)Adds the given line of text to the block element
getStringContent()Returns the strings contained with that block element
+ +

InlineContainerInterface

+ +

If the text contained by your block should be parsed for inline elements, you should also implement the InlineContainerInterface. This doesn’t add any new methods but does signal to the engine that inline parsing is required.

+ +

Multi-line Code Blocks

+ +

If you have a block which spans multiple lines and doesn’t contain any child blocks, consider having isCode() return true. Code blocks have a special feature which enables “greedy parsing” - once it first parses your block, the engine will assume that most of the subsequent lines of Markdown belong to your block - it won’t try using any other parsers until your parser’s matchesNextLine() method returns false, indicating that we’ve reached the end of that code block.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/block-rendering/index.html b/1.0/customization/block-rendering/index.html new file mode 100644 index 0000000000..36803cc1d7 --- /dev/null +++ b/1.0/customization/block-rendering/index.html @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + Block Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Block Rendering

+ +

Block renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement BlockRendererInterface and its render() method:

+ +

render()

+ +
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false);
+
+ +

The HtmlRenderer will call this method whenever a supported block element is encountered in the AST being rendered.

+ +

If the method can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the block and any of its contents. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Block Renderers

+ +

When registering your renderer, you must tell the Environment which block element class your renderer should handle. For example:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the block class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addBlockRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple block types:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Block\Element\IndentedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addBlockRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addBlockRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Node\Block\AbstractBlock;
+use League\CommonMark\Renderer\Block\BlockRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements BlockRendererInterface
+{
+    public function render(AbstractBlock $block, NodeRendererInterface $htmlRenderer, bool $inTightList = false)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addBlockRenderer('League\CommonMark\Block\Element\ThematicBreak', new TextDividerRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/cursor/index.html b/1.0/customization/cursor/index.html new file mode 100644 index 0000000000..f5a5c25479 --- /dev/null +++ b/1.0/customization/cursor/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter()Returns the character at the current position
getCharacter(int $index)Returns the character at the given absolute position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/delimiter-processing/index.html b/1.0/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..84ef963b45 --- /dev/null +++ b/1.0/customization/delimiter-processing/index.html @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse);
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/document-processing/index.html b/1.0/customization/document-processing/index.html new file mode 100644 index 0000000000..334f85ffb5 --- /dev/null +++ b/1.0/customization/document-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/1.0/customization/environment/index.html b/1.0/customization/environment/index.html new file mode 100644 index 0000000000..77f0cd80f8 --- /dev/null +++ b/1.0/customization/environment/index.html @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

A pre-configured Environment can be obtained like this:

+ +
use League\CommonMark;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+ +

All of the core renders, parsers, etc. needed to implement the CommonMark spec will be pre-registered and ready to go.

+ +

You can customize this default Environment (or even a new, empty one) using any of the methods below (from the ConfigurableEnvironmentInterface interface).

+ +

mergeConfig()

+ +
public function mergeConfig(array $config = []);
+
+ +

Merges the given configuration settings into any existing ones.

+ +

setConfig()

+ +
public function setConfig(array $config = []);
+
+ +

Completely replaces the previous configuration settings with the new $config you provide.

+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. This is typically how you’d integrate third-party extensions with this library.

+ +

addBlockParser()

+ +
public function addBlockParser(BlockParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addBlockRenderer()

+ +
public function addBlockRenderer(string $blockClass, BlockRendererInterface $blockRenderer, int $priority = 0);
+
+ +

Registers a BlockRendererInterface to handle a specific type of block ($blockClass) with the given priority (a higher number will be executed earlier).

+ +

See Block Rendering for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addInlineRenderer()

+ +
public function addInlineRenderer(string $inlineClass, InlineRendererInterface $renderer, int $priority = 0);
+
+ +

Registers an InlineRendererInterface to handle a specific type of inline ($inlineClass) with the given priority (a higher number will be executed earlier). +A single renderer can handle multiple inline classes, but you must register it separately for each type. (The same renderer instance can be re-used if desired.)

+ +

See Inline Rendering for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/event-dispatcher/index.html b/1.0/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..ca7865df99 --- /dev/null +++ b/1.0/customization/event-dispatcher/index.html @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code. If you’re familiar with Symfony’s EventDispatcher or PSR-14 then this should be very familiar to you.

+ +

Event Class

+ +

All events must extend from the AbstractEvent class:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - an instance of AbstractEvent to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Inline\Element\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event)
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data['attributes']['class'] = 'external-link';
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfig('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = Environment::createCommonMarkEnvironment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/extensions/index.html b/1.0/customization/extensions/index.html new file mode 100644 index 0000000000..bf73f88cbf --- /dev/null +++ b/1.0/customization/extensions/index.html @@ -0,0 +1,460 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment)
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new EmojiExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ +

Included Extensions

+ +

Starting in v1.3, this library includes several extensions to support GitHub-Flavored Markdown. You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+
+ +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

GFM Extensions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeDocumentation
GithubFlavoredMarkdownExtensionEnables full support for GFM. Includes the following sub-extensions by default: 
AutolinkExtensionEnables automatic linking of URLs within text without needing to wrap them with Markdown syntaxDocumentation
DisallowedRawHtmlExtensionDisables certain kinds of HTML tags that could affect page rendering 
StrikethroughExtensionAllows using tilde characters (~~) for ~strikethrough~ formattingDocumentation
TableExtensionEnables you to create HTML tablesDocumentation
TaskListExtensionAllows the creation of task listsDocumentation
+ +

Other Useful Extensions

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeDocumentation
ExternalLinkExtensionTags external links with additional markupDocumentation
InlinesOnlyExtensionOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.Documentation
SmartPunctExtensionIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalentsDocumentation
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/inline-parsing/index.html b/1.0/customization/inline-parsing/index.html new file mode 100644 index 0000000000..cb0e27013d --- /dev/null +++ b/1.0/customization/inline-parsing/index.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getCharacters()

+ +

This method should return an array of single characters which the inline parser engine should stop on. When it does find a match in the current line the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has stopped at a matching character; and,
  2. +
  3. No other inline parsers have successfully parsed the character
  4. +
+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line/character for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the character will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return ['@'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+        // Save the cursor state in case we need to rewind and bail
+        $previousState = $cursor->saveState();
+        // Advance past the @ symbol to keep parsing simpler
+        $cursor->advance();
+        // Parse the handle
+        $handle = $cursor->match('/^[A-Za-z0-9_]{1,15}(?!\w)/');
+        if (empty($handle)) {
+            // Regex failed to match; this isn't a valid Twitter handle
+            $cursor->restoreState($previousState);
+            return false;
+        }
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Image;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return [':'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // The next character must be a paren; if not, then bail
+        // We use peek() to quickly check without affecting the cursor
+        $nextChar = $cursor->peek();
+        if ($nextChar !== '(' && $nextChar !== ')') {
+            return false;
+        }
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($nextChar === ')') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($nextChar === '(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/inline-rendering/index.html b/1.0/customization/inline-rendering/index.html new file mode 100644 index 0000000000..5f77bdb347 --- /dev/null +++ b/1.0/customization/inline-rendering/index.html @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + Inline Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Inline Rendering

+ +

Inline renderers are responsible for converting the parsed inline elements into their HTML representation.

+ +

All inline renderers should implement InlineRendererInterface and its render() method:

+ +

render()

+ +

Block elements are responsible for calling $htmlRenderer->renderInlines() if they contain inline elements. This in turns causes the HtmlRenderer to call this render() method whenever a supported inline element is encountered.

+ +

If the method can only handle certain inline types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the entire inline and any contents. This can be an HtmlElement object (preferred; castable to a string) or a string of raw HTML.

+ +

You are responsible for handling any escaping that may be necessary.

+ +

Return null if your renderer cannot handle the given inline element - the next-highest priority renderer will then be given a chance to render it.

+ +

Designating Inline Renderers

+ +

When registering your render, you must tell the Environment which inline element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the inline class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addInlineRenderer('League\CommonMark\Inline\Element\Link', new MyCustomLinkRenderer());
+
+ +

Example

+ +

Here’s a custom renderer which puts a special class on links to external sites:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+use League\CommonMark\HtmlElement;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+    private $host;
+
+    public function __construct($host)
+    {
+        $this->host = $host;
+    }
+
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . get_class($inline));
+        }
+
+        $attrs = array();
+
+        $attrs['href'] = $htmlRenderer->escape($inline->getUrl(), true);
+
+        if (isset($inline->attributes['title'])) {
+            $attrs['title'] = $htmlRenderer->escape($inline->data['title'], true);
+        }
+
+        if ($this->isExternalUrl($inline->getUrl())) {
+            $attrs['class'] = 'external-link';
+        }
+
+        return new HtmlElement('a', $attrs, $htmlRenderer->renderInlines($inline->children()));
+    }
+
+    private function isExternalUrl($url)
+    {
+        return parse_url($url, PHP_URL_HOST) !== $this->host;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineRenderer(Link::class, new MyCustomLinkRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/customization/overview/index.html b/1.0/customization/overview/index.html new file mode 100644 index 0000000000..152d7832ba --- /dev/null +++ b/1.0/customization/overview/index.html @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

This library uses a three-step process to convert Markdown to HTML:

+ +
    +
  1. Parse the various block and inline elements into an Abstract Syntax Tree (AST)
  2. +
  3. Allow users to iterate and modify the parsed AST
  4. +
  5. Render the final AST representation to HTML
  6. +
+ +

You can hook into any of these three steps to customize this library to suit your needs.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renders convert the parsed blocks/inlines from the AST representation into HTML. There are two types of renderers:

+ + + +

When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you +to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/index.html b/1.0/index.html new file mode 100644 index 0000000000..db0cbe4e9e --- /dev/null +++ b/1.0/index.html @@ -0,0 +1,352 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/installation/index.html b/1.0/installation/index.html new file mode 100644 index 0000000000..06592eaf27 --- /dev/null +++ b/1.0/installation/index.html @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +

In your project root just run:

+ +
composer require league/commonmark:^1.0
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^1.0. This is equivalent to >=1.0 <2.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/security/index.html b/1.0/security/index.html new file mode 100644 index 0000000000..1f5c37d251 --- /dev/null +++ b/1.0/security/index.html @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.0/upgrading/index.html b/1.0/upgrading/index.html new file mode 100644 index 0000000000..eac1a84873 --- /dev/null +++ b/1.0/upgrading/index.html @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + Upgrading from 0.19 to 1.0 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.0. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 0.19 to 1.0

+ +

Previous Deprecations Removed

+ +

All previously-deprecated code has been removed. This includes:

+ + + +

Document Processors Removed

+ +

We no longer support Document Processors because we now have event dispatching which can fill that same role! Simply remove the interface from your processor and register it as a listener; for example, instead of this:

+ +
class MyDocumentProcessor implements DocumentProcessorInterface
+{
+    public function processDocument(Document $document)
+    {
+        // TODO: Do things with the $document
+    }
+}
+
+// ...
+
+$processor = new MyDocumentProcessor();
+$environment->addDocumentProcessor($processor);
+
+ +

Simply do this:

+ +
class MyDocumentProcessor
+{
+    public function onDocumentParsed(DocumentParsedEvent $event)
+    {
+        $document = $event->getDocument();
+        // TODO: Do things with the $document
+    }
+}
+
+// ...
+
+$processor = new MyDocumentProcessor();
+$environment->addEventListener(DocumentParsedEvent::class, [$processor, 'onDocumentParsed']);
+
+ +

Text Encoding

+ +

This library used to claim it supported ISO-8859-1 encoding but that never truly worked - everything assumed the text was encoded as UTF-8 or ASCII. We’ve therefore dropped support for ISO-8859-1 and any other unexpected encodings. If you were using some other encoding, you’ll now need to convert your Markdown to UTF-8 prior to running it through this library.

+ +

Additionally, all public getEncoding() or setEncoding() methods have been removed, so assume that you’re working with UTF-8.

+ +

Inline Processors

+ +

The “inline processor” functionality has been removed and replaced with a proper “delimiter processor” feature geared specifically towards dealing with delimiters (which is what the previous implementation tried to do - poorly).

+ +

No direct upgrade path exists as this implementation was not widely used, or only used for implementing delimiter processing. If you fall in the latter category, simply leverage the new functionality instead. Otherwise, if you have another good use case for inline processors, please let us know in the issue tracker.

+ +

Delimiters

+ +

Now that we have proper delimiter handling, we’ve finalized the Delimiter class and extracted a DelimiterInterface from it. If you previous extended from Delimiter you’ll need to implement this new interface instead.

+ +

We also deleted these unused Delimiter methods:

+ + + +

And all of the remaining Delimiter::set___() methods no longer return $this.

+ +

DocParser

+ +

The DocParser class is now final as it was never intended to be extended, especially given how so much logic was in private methods. Any custom implementations should implement the new DocParserInterface interface instead.

+ +

Additionally, the getEnvironment() method has been deprecated and excluded from that new interface, as it was only used internally by the DocParser and other better ways exist to obtain an environment where needed.

+ +

Configuration

+ +

The Configuration class is now final and implements a new ConfigurationInterface. If any of your parsers/renders/etc implement ConfigurationAwareInterface you’ll need to update that method to accept the new interface instead of the concrete class.

+ +

We also renamed/added the following methods:

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Old NameNew Name
getConfig()get()
n/aset()
setConfig()replace()
mergeConfig()merge()
+ +

AbstractInlineContainer

+ +

The AbstractInlineContainer class added an unnecessary level of inheritance and was therefore deprecated. If you previously extended this class, you should now extend from AbstractInline and override isContainer() to return true.

+ +

AdjoiningTextCollapser

+ +

The AdjoiningTextCollapser is an internal class used to combine multiple Text elements into one. If you were using this yourself (unlikely) you’ll need to refer to its new name instead: AdjacentTextMerger. And if you previously used collapseTextNodes() you’ll want to switch to using mergeChildNodes() instead.

+ +

References

+ +

The ReferenceParser was moved into the Reference sub-namespace, so update your imports accordingly.

+ +

Virtually all usages of ReferenceMap in type hints have been replaced with the new ReferenceMapInterface. This interface has the same methods, with one small change: addReference() no longer returns $this.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/basic-usage/index.html b/1.3/basic-usage/index.html new file mode 100644 index 0000000000..a7217f2f02 --- /dev/null +++ b/1.3/basic-usage/index.html @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

The actual conversion process has three steps:

+ +
    +
  1. Creating an Environment, adding whichever extensions/parser/renders you need
  2. +
  3. Parsing the Markdown input into an AST
  4. +
  5. Rendering the AST document as HTML
  6. +
+ +

CommonMarkConverter handles this for you, but you can execute that process yourself if you wish:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+// <h1>Hello World!</h1>
+
+ +

Additional customization is also possible, and we have many handy extensions to enable additional syntax and features.

+ +

Supported Character Encodings

+ +

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.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/changelog/index.html b/1.3/changelog/index.html new file mode 100644 index 0000000000..10953bd184 --- /dev/null +++ b/1.3/changelog/index.html @@ -0,0 +1,724 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 1.x releases are shown below. See the full list of releases for the complete changelog.

+ +

1.3.4 - 2020-04-13

+ +

Fixed

+ + + +

1.3.3 - 2020-04-05

+ +

Fixed

+ + + +

1.3.2 - 2020-03-25

+ +

Fixed

+ + + +

1.3.1 - 2020-02-28

+ +

Fixed

+ + + +

1.3.0 - 2020-02-09

+ +

ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.

+ +

Added

+ + + +

Changed

+ + + +

1.2.2 - 2020-01-16

+ +

This release contains the same changes as 1.1.3:

+ +

Fixed

+ + + +

1.1.3 - 2020-01-16

+ +

Fixed

+ + + +

1.2.1 - 2020-01-15

+ +

Changed

+ + + +

1.2.0 - 2020-01-09

+ +

Changed

+ + + +

1.1.2 - 2019-12-10

+ +

Fixed

+ + + +

1.1.1 - 2019-11-11

+ +

Fixed

+ + + +

1.1.0 - 2019-10-31

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.0.0 - 2019-06-29

+ +

First stable release! 🎉

+ +

No code changes have been introduced since 1.0.0-rc1

+ +

1.0.0-rc1 - 2019-06-20

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

1.0.0-beta4 - 2019-06-05

+ +

Added

+ + + +

Removed

+ + + +

1.0.0-beta3 - 2019-05-28

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta2 - 2019-05-27

+ +

This beta release fixes a couple of items that were not addressed in the previous beta.

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta1 - 2019-05-26

+ +

See the upgrading guide for additional information.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

Removed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/command-line/index.html b/1.3/command-line/index.html new file mode 100644 index 0000000000..0eb825f4be --- /dev/null +++ b/1.3/command-line/index.html @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + Command Line - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Command Line

+ +

Markdown can be converted at the command line using the ./bin/commonmark script.

+ +

Usage

+ +
./bin/commonmark [OPTIONS] [FILE]
+
+ + + +

If no file is given, input will be read from STDIN.

+ +

Output will be written to STDOUT.

+ +

Examples

+ +

Converting a file named document.md

+ +
./bin/commonmark document.md
+
+ +

Converting a file and saving its output

+ +
./bin/commonmark document.md > output.html
+
+ +

Converting from STDIN

+ +
echo -e '# Hello World!' | ./bin/commonmark
+
+ +

Converting from STDIN and saving the output

+ +
echo -e '# Hello World!' | ./bin/commonmark > output.html
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/configuration/index.html b/1.3/configuration/index.html new file mode 100644 index 0000000000..e2c1df4aae --- /dev/null +++ b/1.3/configuration/index.html @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

You can provide an array of configuration options to the CommonMarkConverter when creating it:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter([
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'enable_em' => true,
+    'enable_strong' => true,
+    'use_asterisk' => true,
+    'use_underscore' => true,
+    'unordered_list_markers' => ['-', '*', '+'],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => INF,
+]);
+
+ +

Here’s a list of currently-supported options:

+ + + +

Additional configuration options are available for some of the available extensions - refer to their individual documentation for more details.

+ +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

The Environment also exposes three methods for managing the configuration:

+ + + +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/abstract-syntax-tree/index.html b/1.3/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..9a9efab169 --- /dev/null +++ b/1.3/customization/abstract-syntax-tree/index.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Traversal

+ +

The following methods can be used to traverse the AST:

+ + + +

Iteration / Walking the Tree

+ +

If you’d like to iterate through all the nodes, use the walker() method to obtain an instance of NodeWalker. This will walk through the entire tree, emitting NodeWalkerEvents along the way.

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'I am ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

This walker doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes.

+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/block-parsing/index.html b/1.3/customization/block-parsing/index.html new file mode 100644 index 0000000000..94383af563 --- /dev/null +++ b/1.3/customization/block-parsing/index.html @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

Block parsers should implement BlockParserInterface and implement the following method:

+ +

parse()

+ +
public function parse(ContextInterface $context, Cursor $cursor): bool;
+
+ +

When parsing a new line, the DocParser iterates through all registered block parsers and calls their parse() method. Each parser must determine whether it can handle the given line; if so, it should parse the given block and return true.

+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the line will be parsed as text.

+ +

Returning true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of syntax indicating the block start
  2. +
  3. Add the parsed block via $context->addBlock()
  4. +
+ +

Tips

+ + + +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

Block elements also play a role during the parsing process as they tell the underlying engine how to handle subsequent blocks that are found.

+ +

AbstractBlockElement Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
canContain(...)Tell the engine whether a subsequent block can be added as a child of yours
isCode()Returns whether this block represents an extra-greedy <code> block
matchesNextLine(...)Returns whether this block continues onto the next line (some blocks are multi-line)
shouldLastLineBeBlank()Returns whether the last line should be blank (primarily used by ListItem elements)
finalize(...)Finalizes the block after all child items have been added, thus marking it as closed for modification
+ +

For examples on how these methods are used, see the core block element classes included with this library.

+ +

AbstractStringContainerBlock

+ +

If your element can contain strings of text, you should extend AbstractStringContainerBlock instead of AbstractBlock. This provides some additional methods needed to manage that inner text:

+ + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
handleRemainingContents(...)This is called when a block has been created but some other text still exists on that line
addLine(...)Adds the given line of text to the block element
getStringContent()Returns the strings contained with that block element
+ +

InlineContainerInterface

+ +

If the text contained by your block should be parsed for inline elements, you should also implement the InlineContainerInterface. This doesn’t add any new methods but does signal to the engine that inline parsing is required.

+ +

Multi-line Code Blocks

+ +

If you have a block which spans multiple lines and doesn’t contain any child blocks, consider having isCode() return true. Code blocks have a special feature which enables “greedy parsing” - once it first parses your block, the engine will assume that most of the subsequent lines of Markdown belong to your block - it won’t try using any other parsers until your parser’s matchesNextLine() method returns false, indicating that we’ve reached the end of that code block.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/block-rendering/index.html b/1.3/customization/block-rendering/index.html new file mode 100644 index 0000000000..c80b1a40db --- /dev/null +++ b/1.3/customization/block-rendering/index.html @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + Block Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Block Rendering

+ +

Block renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement BlockRendererInterface and its render() method:

+ +

render()

+ +
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false);
+
+ +

The HtmlRenderer will call this method whenever a supported block element is encountered in the AST being rendered.

+ +

If the method can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the block and any of its contents. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Block Renderers

+ +

When registering your renderer, you must tell the Environment which block element class your renderer should handle. For example:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the block class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addBlockRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple block types:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Block\Element\IndentedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addBlockRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addBlockRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Node\Block\AbstractBlock;
+use League\CommonMark\Renderer\Block\BlockRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements BlockRendererInterface
+{
+    public function render(AbstractBlock $block, NodeRendererInterface $htmlRenderer, bool $inTightList = false)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addBlockRenderer('League\CommonMark\Block\Element\ThematicBreak', new TextDividerRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/cursor/index.html b/1.3/customization/cursor/index.html new file mode 100644 index 0000000000..f1f320ba8b --- /dev/null +++ b/1.3/customization/cursor/index.html @@ -0,0 +1,499 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter()Returns the character at the current position
getCharacter(int $index)Returns the character at the given absolute position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/delimiter-processing/index.html b/1.3/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..90777f3e2c --- /dev/null +++ b/1.3/customization/delimiter-processing/index.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse);
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/document-processing/index.html b/1.3/customization/document-processing/index.html new file mode 100644 index 0000000000..aee20caf76 --- /dev/null +++ b/1.3/customization/document-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/1.3/customization/environment/index.html b/1.3/customization/environment/index.html new file mode 100644 index 0000000000..b5a2958d4c --- /dev/null +++ b/1.3/customization/environment/index.html @@ -0,0 +1,460 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

A pre-configured Environment can be obtained like this:

+ +
use League\CommonMark;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+ +

All of the core renders, parsers, etc. needed to implement the CommonMark spec will be pre-registered and ready to go.

+ +

You can customize this default Environment (or even a new, empty one) using any of the methods below (from the ConfigurableEnvironmentInterface interface).

+ +

mergeConfig()

+ +
public function mergeConfig(array $config = []);
+
+ +

Merges the given configuration settings into any existing ones.

+ +

setConfig()

+ +
public function setConfig(array $config = []);
+
+ +

Completely replaces the previous configuration settings with the new $config you provide.

+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. This is typically how you’d integrate third-party extensions with this library.

+ +

addBlockParser()

+ +
public function addBlockParser(BlockParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addBlockRenderer()

+ +
public function addBlockRenderer(string $blockClass, BlockRendererInterface $blockRenderer, int $priority = 0);
+
+ +

Registers a BlockRendererInterface to handle a specific type of block ($blockClass) with the given priority (a higher number will be executed earlier).

+ +

See Block Rendering for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addInlineRenderer()

+ +
public function addInlineRenderer(string $inlineClass, InlineRendererInterface $renderer, int $priority = 0);
+
+ +

Registers an InlineRendererInterface to handle a specific type of inline ($inlineClass) with the given priority (a higher number will be executed earlier). +A single renderer can handle multiple inline classes, but you must register it separately for each type. (The same renderer instance can be re-used if desired.)

+ +

See Inline Rendering for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/event-dispatcher/index.html b/1.3/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..85850b97cf --- /dev/null +++ b/1.3/customization/event-dispatcher/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code. If you’re familiar with Symfony’s EventDispatcher or PSR-14 then this should be very familiar to you.

+ +

Event Class

+ +

All events must extend from the AbstractEvent class:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - an instance of AbstractEvent to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Inline\Element\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event)
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data['attributes']['class'] = 'external-link';
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfig('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = Environment::createCommonMarkEnvironment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/extensions/index.html b/1.3/customization/extensions/index.html new file mode 100644 index 0000000000..abcb064d30 --- /dev/null +++ b/1.3/customization/extensions/index.html @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment)
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new EmojiExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/inline-parsing/index.html b/1.3/customization/inline-parsing/index.html new file mode 100644 index 0000000000..8165f1e61c --- /dev/null +++ b/1.3/customization/inline-parsing/index.html @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getCharacters()

+ +

This method should return an array of single characters which the inline parser engine should stop on. When it does find a match in the current line the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has stopped at a matching character; and,
  2. +
  3. No other inline parsers have successfully parsed the character
  4. +
+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line/character for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the character will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return ['@'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+        // Save the cursor state in case we need to rewind and bail
+        $previousState = $cursor->saveState();
+        // Advance past the @ symbol to keep parsing simpler
+        $cursor->advance();
+        // Parse the handle
+        $handle = $cursor->match('/^[A-Za-z0-9_]{1,15}(?!\w)/');
+        if (empty($handle)) {
+            // Regex failed to match; this isn't a valid Twitter handle
+            $cursor->restoreState($previousState);
+            return false;
+        }
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Image;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return [':'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // The next character must be a paren; if not, then bail
+        // We use peek() to quickly check without affecting the cursor
+        $nextChar = $cursor->peek();
+        if ($nextChar !== '(' && $nextChar !== ')') {
+            return false;
+        }
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($nextChar === ')') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($nextChar === '(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/inline-rendering/index.html b/1.3/customization/inline-rendering/index.html new file mode 100644 index 0000000000..a8a673feeb --- /dev/null +++ b/1.3/customization/inline-rendering/index.html @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + Inline Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Inline Rendering

+ +

Inline renderers are responsible for converting the parsed inline elements into their HTML representation.

+ +

All inline renderers should implement InlineRendererInterface and its render() method:

+ +

render()

+ +

Block elements are responsible for calling $htmlRenderer->renderInlines() if they contain inline elements. This in turns causes the HtmlRenderer to call this render() method whenever a supported inline element is encountered.

+ +

If the method can only handle certain inline types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the entire inline and any contents. This can be an HtmlElement object (preferred; castable to a string) or a string of raw HTML.

+ +

You are responsible for handling any escaping that may be necessary.

+ +

Return null if your renderer cannot handle the given inline element - the next-highest priority renderer will then be given a chance to render it.

+ +

Designating Inline Renderers

+ +

When registering your render, you must tell the Environment which inline element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the inline class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addInlineRenderer('League\CommonMark\Inline\Element\Link', new MyCustomLinkRenderer());
+
+ +

Example

+ +

Here’s a custom renderer which puts a special class on links to external sites:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+use League\CommonMark\HtmlElement;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+    private $host;
+
+    public function __construct($host)
+    {
+        $this->host = $host;
+    }
+
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . get_class($inline));
+        }
+
+        $attrs = array();
+
+        $attrs['href'] = $htmlRenderer->escape($inline->getUrl(), true);
+
+        if (isset($inline->attributes['title'])) {
+            $attrs['title'] = $htmlRenderer->escape($inline->data['title'], true);
+        }
+
+        if ($this->isExternalUrl($inline->getUrl())) {
+            $attrs['class'] = 'external-link';
+        }
+
+        return new HtmlElement('a', $attrs, $htmlRenderer->renderInlines($inline->children()));
+    }
+
+    private function isExternalUrl($url)
+    {
+        return parse_url($url, PHP_URL_HOST) !== $this->host;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineRenderer(Link::class, new MyCustomLinkRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/customization/overview/index.html b/1.3/customization/overview/index.html new file mode 100644 index 0000000000..96d6db4e81 --- /dev/null +++ b/1.3/customization/overview/index.html @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

This library uses a three-step process to convert Markdown to HTML:

+ +
    +
  1. Parse the various block and inline elements into an Abstract Syntax Tree (AST)
  2. +
  3. Allow users to iterate and modify the parsed AST
  4. +
  5. Render the final AST representation to HTML
  6. +
+ +

You can hook into any of these three steps to customize this library to suit your needs.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renders convert the parsed blocks/inlines from the AST representation into HTML. There are two types of renderers:

+ + + +

When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you +to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/autolinks/index.html b/1.3/extensions/autolinks/index.html new file mode 100644 index 0000000000..71a9537725 --- /dev/null +++ b/1.3/extensions/autolinks/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

It also provides a parser to autolink @mentions to Twitter, GitHub, or any custom service you wish, though this is disabled by default.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

This extension also provides functionality to automatically link “mentions” like @colinodell to Twitter, GitHub, or any other site of your choice!

+ +

For Twitter:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\InlineMentionParser;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(InlineMentionParser::createTwitterHandleParser());
+
+// TODO: Instantiate your converter and convert some Markdown
+
+ +

For GitHub:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\InlineMentionParser;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(InlineMentionParser::createGithubHandleParser());
+
+// TODO: Instantiate your converter and convert some Markdown
+
+ +

Or configure your own custom one:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\InlineMentionParser;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new InlineMentionParser('https://www.example.com/users/%s/profile'));
+
+// TODO: Instantiate your converter and convert some Markdown
+
+ +

When creating your own, you can provide two parameters to the constructor:

+ + + +

Note that @mention-style linking doesn’t actually require you to add the extension - just the InlineParser of your choice.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/commonmark/index.html b/1.3/extensions/commonmark/index.html new file mode 100644 index 0000000000..840e543393 --- /dev/null +++ b/1.3/extensions/commonmark/index.html @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically included for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Or if you call the Environment::createCommonMarkEnvironment() helper:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\CommonMarkCoreExtension;
+use League\CommonMark\HtmlRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/disallowed-raw-html/index.html b/1.3/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..befb012fa7 --- /dev/null +++ b/1.3/extensions/disallowed-raw-html/index.html @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically filters certain HTML tags when rendering output, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('I cannot change the page <title>anymore</title>');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/external-links/index.html b/1.3/extensions/external-links/index.html new file mode 100644 index 0000000000..4733ec40bf --- /dev/null +++ b/1.3/extensions/external-links/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Set your configuration
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\HtmlElement;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+
+    /**
+     * @param Link                     $inline
+     * @param ElementRendererInterface $htmlRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . \get_class($inline));
+        }
+
+        if ($inline->getData('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/github-flavored-markdown/index.html b/1.3/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..8cfbe1797b --- /dev/null +++ b/1.3/extensions/github-flavored-markdown/index.html @@ -0,0 +1,414 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/inlines-only/index.html b/1.3/extensions/inlines-only/index.html new file mode 100644 index 0000000000..84ff7ebd2c --- /dev/null +++ b/1.3/extensions/inlines-only/index.html @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+
+// Create a new, empty environment
+$environment = new Environment();
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/overview/index.html b/1.3/extensions/overview/index.html new file mode 100644 index 0000000000..cdb47df467 --- /dev/null +++ b/1.3/extensions/overview/index.html @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/smart-punctuation/index.html b/1.3/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..bea356e31f --- /dev/null +++ b/1.3/extensions/smart-punctuation/index.html @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Set your configuration
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/strikethrough/index.html b/1.3/extensions/strikethrough/index.html new file mode 100644 index 0000000000..3a2dc1171c --- /dev/null +++ b/1.3/extensions/strikethrough/index.html @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/tables/index.html b/1.3/extensions/tables/index.html new file mode 100644 index 0000000000..212e995518 --- /dev/null +++ b/1.3/extensions/tables/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Table\TableExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/extensions/task-lists/index.html b/1.3/extensions/task-lists/index.html new file mode 100644 index 0000000000..81a086df44 --- /dev/null +++ b/1.3/extensions/task-lists/index.html @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convertToHtml($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/index.html b/1.3/index.html new file mode 100644 index 0000000000..6b23d2e5ca --- /dev/null +++ b/1.3/index.html @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/installation/index.html b/1.3/installation/index.html new file mode 100644 index 0000000000..b33fccf635 --- /dev/null +++ b/1.3/installation/index.html @@ -0,0 +1,380 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +

In your project root just run:

+ +
composer require league/commonmark:^1.3
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^1.3. This is equivalent to >=1.3 <2.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/security/index.html b/1.3/security/index.html new file mode 100644 index 0000000000..505feed27b --- /dev/null +++ b/1.3/security/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.3/upgrading/index.html b/1.3/upgrading/index.html new file mode 100644 index 0000000000..742ba1efcc --- /dev/null +++ b/1.3/upgrading/index.html @@ -0,0 +1,387 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.x - 1.3 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.3. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 1.x to 1.3

+ +

There are no breaking changes introduced in 1.3, but we did move most of our extensions into the core library.

+ +

GitHub-Flavored Markdown and other official extensions

+ +

Previously, anyone wanting GFM support had to install additional libraries like league/commonmark-extras. This is no longer required as GFM support is now built into this library! This is also true for other official extensions like league/commonmark-ext-inlines-only.

+ +

If you were previously using any of the league/commonmark-ext* libraries:

+ + + +

See the GitHub-Flavored Markdown extension documentation for more information on using this extension. Additional details can also be found in Colin O’Dell’s blog post.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/basic-usage/index.html b/1.4/basic-usage/index.html new file mode 100644 index 0000000000..c72b9c6667 --- /dev/null +++ b/1.4/basic-usage/index.html @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

Additional customization is also possible, and we have many handy extensions to enable additional syntax and features.

+ +

Supported Character Encodings

+ +

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.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/changelog/index.html b/1.4/changelog/index.html new file mode 100644 index 0000000000..2e17058df5 --- /dev/null +++ b/1.4/changelog/index.html @@ -0,0 +1,1056 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 1.x releases are shown below. See the full list of releases for the complete changelog.

+ +

1.6.7 - 2022-01-13

+ +

Changed

+ + + +

1.6.6 - 2021-07-17

+ +

Fixed

+ + + +

1.6.5 - 2021-06-26

+ +

Changed

+ + + +

Fixed

+ + + +

1.6.4 - 2021-06-19

+ +

Changed

+ + + +

1.6.3 - 2021-06-19

+ +

Fixed

+ + + +

1.6.2 - 2021-05-12

+ +

Fixed

+ + + +

1.6.1 - 2021-05-08

+ +

Fixed

+ + + +

1.6.0 - 2021-05-01

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

Fixed

+ + + +

1.5.8 - 2021-03-28

+ +

Fixed

+ + + +

1.5.7 - 2020-10-31

+ +

Fixed

+ + + +

1.5.6 - 2020-10-17

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.5 - 2020-09-13

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.4 - 2020-08-18

+ +

Fixed

+ + + +

1.5.3 - 2020-07-19

+ +

Fixed

+ + + +

1.5.2 - 2020-07-19

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.1 - 2020-06-27

+ +

Fixed

+ + + +

1.5.0 - 2020-06-21

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.4.3 - 2020-05-04

+ +

Fixed

+ + + +

1.4.2 - 2020-04-24

+ +

Fixed

+ + + +

1.4.1 - 2020-04-20

+ +

Fixed

+ + + +

1.4.0 - 2020-04-18

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.3.4 - 2020-04-13

+ +

Fixed

+ + + +

1.3.3 - 2020-04-05

+ +

Fixed

+ + + +

1.3.2 - 2020-03-25

+ +

Fixed

+ + + +

1.3.1 - 2020-02-28

+ +

Fixed

+ + + +

1.3.0 - 2020-02-09

+ +

ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.

+ +

Added

+ + + +

Changed

+ + + +

1.2.2 - 2020-01-16

+ +

This release contains the same changes as 1.1.3:

+ +

Fixed

+ + + +

1.1.3 - 2020-01-16

+ +

Fixed

+ + + +

1.2.1 - 2020-01-15

+ +

Changed

+ + + +

1.2.0 - 2020-01-09

+ +

Changed

+ + + +

1.1.2 - 2019-12-10

+ +

Fixed

+ + + +

1.1.1 - 2019-11-11

+ +

Fixed

+ + + +

1.1.0 - 2019-10-31

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.0.0 - 2019-06-29

+ +

First stable release! 🎉

+ +

No code changes have been introduced since 1.0.0-rc1

+ +

1.0.0-rc1 - 2019-06-20

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

1.0.0-beta4 - 2019-06-05

+ +

Added

+ + + +

Removed

+ + + +

1.0.0-beta3 - 2019-05-28

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta2 - 2019-05-27

+ +

This beta release fixes a couple of items that were not addressed in the previous beta.

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta1 - 2019-05-26

+ +

See the upgrading guide for additional information.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

Removed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/command-line/index.html b/1.4/command-line/index.html new file mode 100644 index 0000000000..b6eaab0b18 --- /dev/null +++ b/1.4/command-line/index.html @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + Command Line - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Command Line

+ +

This functionality has been deprecated in version 1.4 and will be removed in 2.0.

+ +

Markdown can be converted at the command line using the ./bin/commonmark script.

+ +

Usage

+ +
./bin/commonmark [OPTIONS] [FILE]
+
+ + + +

If no file is given, input will be read from STDIN.

+ +

Output will be written to STDOUT.

+ +

Examples

+ +

Converting a file named document.md

+ +
./bin/commonmark document.md
+
+ +

Converting a file and saving its output

+ +
./bin/commonmark document.md > output.html
+
+ +

Converting from STDIN

+ +
echo -e '# Hello World!' | ./bin/commonmark
+
+ +

Converting from STDIN and saving the output

+ +
echo -e '# Hello World!' | ./bin/commonmark > output.html
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/configuration/index.html b/1.4/configuration/index.html new file mode 100644 index 0000000000..ab8f913dac --- /dev/null +++ b/1.4/configuration/index.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

You can provide an array of configuration options to the CommonMarkConverter when creating it:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter([
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'enable_em' => true,
+    'enable_strong' => true,
+    'use_asterisk' => true,
+    'use_underscore' => true,
+    'unordered_list_markers' => ['-', '*', '+'],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => INF,
+]);
+
+ +

Here’s a list of currently-supported options:

+ + + +

Additional configuration options are available for some of the available extensions - refer to their individual documentation for more details.

+ +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

The Environment also exposes three methods for managing the configuration:

+ + + +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/abstract-syntax-tree/index.html b/1.4/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..bbb0aef252 --- /dev/null +++ b/1.4/customization/abstract-syntax-tree/index.html @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Traversal

+ +

The following methods can be used to traverse the AST:

+ + + +

Iteration / Walking the Tree

+ +

If you’d like to iterate through all the nodes, use the walker() method to obtain an instance of NodeWalker. This will walk through the entire tree, emitting NodeWalkerEvents along the way.

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'I am ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

This walker doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes.

+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/block-parsing/index.html b/1.4/customization/block-parsing/index.html new file mode 100644 index 0000000000..fad65c8ebb --- /dev/null +++ b/1.4/customization/block-parsing/index.html @@ -0,0 +1,485 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

Block parsers should implement BlockParserInterface and implement the following method:

+ +

parse()

+ +
public function parse(ContextInterface $context, Cursor $cursor): bool;
+
+ +

When parsing a new line, the DocParser iterates through all registered block parsers and calls their parse() method. Each parser must determine whether it can handle the given line; if so, it should parse the given block and return true.

+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the line will be parsed as text.

+ +

Returning true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of syntax indicating the block start
  2. +
  3. Add the parsed block via $context->addBlock()
  4. +
+ +

Tips

+ + + +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

Block elements also play a role during the parsing process as they tell the underlying engine how to handle subsequent blocks that are found.

+ +

AbstractBlockElement Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
canContain(...)Tell the engine whether a subsequent block can be added as a child of yours
isCode()Returns whether this block represents an extra-greedy <code> block
matchesNextLine(...)Returns whether this block continues onto the next line (some blocks are multi-line)
shouldLastLineBeBlank()Returns whether the last line should be blank (primarily used by ListItem elements)
finalize(...)Finalizes the block after all child items have been added, thus marking it as closed for modification
+ +

For examples on how these methods are used, see the core block element classes included with this library.

+ +

AbstractStringContainerBlock

+ +

If your element can contain strings of text, you should extend AbstractStringContainerBlock instead of AbstractBlock. This provides some additional methods needed to manage that inner text:

+ + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
handleRemainingContents(...)This is called when a block has been created but some other text still exists on that line
addLine(...)Adds the given line of text to the block element
getStringContent()Returns the strings contained with that block element
+ +

InlineContainerInterface

+ +

If the text contained by your block should be parsed for inline elements, you should also implement the InlineContainerInterface. This doesn’t add any new methods but does signal to the engine that inline parsing is required.

+ +

Multi-line Code Blocks

+ +

If you have a block which spans multiple lines and doesn’t contain any child blocks, consider having isCode() return true. Code blocks have a special feature which enables “greedy parsing” - once it first parses your block, the engine will assume that most of the subsequent lines of Markdown belong to your block - it won’t try using any other parsers until your parser’s matchesNextLine() method returns false, indicating that we’ve reached the end of that code block.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/block-rendering/index.html b/1.4/customization/block-rendering/index.html new file mode 100644 index 0000000000..b2b6371ceb --- /dev/null +++ b/1.4/customization/block-rendering/index.html @@ -0,0 +1,471 @@ + + + + + + + + + + + + + + + + + Block Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Block Rendering

+ +

Block renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement BlockRendererInterface and its render() method:

+ +

render()

+ +
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false);
+
+ +

The HtmlRenderer will call this method whenever a supported block element is encountered in the AST being rendered.

+ +

If the method can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the block and any of its contents. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Block Renderers

+ +

When registering your renderer, you must tell the Environment which block element class your renderer should handle. For example:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the block class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addBlockRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple block types:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Block\Element\IndentedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addBlockRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addBlockRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Node\Block\AbstractBlock;
+use League\CommonMark\Renderer\Block\BlockRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements BlockRendererInterface
+{
+    public function render(AbstractBlock $block, NodeRendererInterface $htmlRenderer, bool $inTightList = false)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addBlockRenderer('League\CommonMark\Block\Element\ThematicBreak', new TextDividerRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/cursor/index.html b/1.4/customization/cursor/index.html new file mode 100644 index 0000000000..ad0a791e86 --- /dev/null +++ b/1.4/customization/cursor/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter()Returns the character at the current position
getCharacter(int $index)Returns the character at the given absolute position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/delimiter-processing/index.html b/1.4/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..4116747c11 --- /dev/null +++ b/1.4/customization/delimiter-processing/index.html @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse);
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/document-processing/index.html b/1.4/customization/document-processing/index.html new file mode 100644 index 0000000000..88af653ef9 --- /dev/null +++ b/1.4/customization/document-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/1.4/customization/environment/index.html b/1.4/customization/environment/index.html new file mode 100644 index 0000000000..e660ec8fbf --- /dev/null +++ b/1.4/customization/environment/index.html @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

A pre-configured Environment can be obtained like this:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+ +

All of the core renders, parsers, etc. needed to implement the CommonMark spec will be pre-registered and ready to go.

+ +

You can customize this default Environment (or even a new, empty one) using any of the methods below (from the ConfigurableEnvironmentInterface interface).

+ +

mergeConfig()

+ +
public function mergeConfig(array $config = []);
+
+ +

Merges the given configuration settings into any existing ones.

+ +

setConfig()

+ +
public function setConfig(array $config = []);
+
+ +

Completely replaces the previous configuration settings with the new $config you provide.

+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. This is typically how you’d integrate third-party extensions with this library.

+ +

addBlockParser()

+ +
public function addBlockParser(BlockParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addBlockRenderer()

+ +
public function addBlockRenderer(string $blockClass, BlockRendererInterface $blockRenderer, int $priority = 0);
+
+ +

Registers a BlockRendererInterface to handle a specific type of block ($blockClass) with the given priority (a higher number will be executed earlier).

+ +

See Block Rendering for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addInlineRenderer()

+ +
public function addInlineRenderer(string $inlineClass, InlineRendererInterface $renderer, int $priority = 0);
+
+ +

Registers an InlineRendererInterface to handle a specific type of inline ($inlineClass) with the given priority (a higher number will be executed earlier). +A single renderer can handle multiple inline classes, but you must register it separately for each type. (The same renderer instance can be re-used if desired.)

+ +

See Inline Rendering for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/event-dispatcher/index.html b/1.4/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..cf20ce5719 --- /dev/null +++ b/1.4/customization/event-dispatcher/index.html @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code. If you’re familiar with Symfony’s EventDispatcher or PSR-14 then this should be very familiar to you.

+ +

Event Class

+ +

All events must extend from the AbstractEvent class:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - an instance of AbstractEvent to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Inline\Element\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event)
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data['attributes']['class'] = 'external-link';
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfig('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = Environment::createCommonMarkEnvironment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/extensions/index.html b/1.4/customization/extensions/index.html new file mode 100644 index 0000000000..6f1b5ce01d --- /dev/null +++ b/1.4/customization/extensions/index.html @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment)
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new EmojiExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/inline-parsing/index.html b/1.4/customization/inline-parsing/index.html new file mode 100644 index 0000000000..fc2d66dfde --- /dev/null +++ b/1.4/customization/inline-parsing/index.html @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getCharacters()

+ +

This method should return an array of single characters which the inline parser engine should stop on. When it does find a match in the current line the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has stopped at a matching character; and,
  2. +
  3. No other inline parsers have successfully parsed the character
  4. +
+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line/character for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the character will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return ['@'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+        // Save the cursor state in case we need to rewind and bail
+        $previousState = $cursor->saveState();
+        // Advance past the @ symbol to keep parsing simpler
+        $cursor->advance();
+        // Parse the handle
+        $handle = $cursor->match('/^[A-Za-z0-9_]{1,15}(?!\w)/');
+        if (empty($handle)) {
+            // Regex failed to match; this isn't a valid Twitter handle
+            $cursor->restoreState($previousState);
+            return false;
+        }
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Image;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return [':'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // The next character must be a paren; if not, then bail
+        // We use peek() to quickly check without affecting the cursor
+        $nextChar = $cursor->peek();
+        if ($nextChar !== '(' && $nextChar !== ')') {
+            return false;
+        }
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($nextChar === ')') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($nextChar === '(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/inline-rendering/index.html b/1.4/customization/inline-rendering/index.html new file mode 100644 index 0000000000..d3797e1d21 --- /dev/null +++ b/1.4/customization/inline-rendering/index.html @@ -0,0 +1,471 @@ + + + + + + + + + + + + + + + + + Inline Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Inline Rendering

+ +

Inline renderers are responsible for converting the parsed inline elements into their HTML representation.

+ +

All inline renderers should implement InlineRendererInterface and its render() method:

+ +

render()

+ +

Block elements are responsible for calling $htmlRenderer->renderInlines() if they contain inline elements. This in turns causes the HtmlRenderer to call this render() method whenever a supported inline element is encountered.

+ +

If the method can only handle certain inline types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the entire inline and any contents. This can be an HtmlElement object (preferred; castable to a string) or a string of raw HTML.

+ +

You are responsible for handling any escaping that may be necessary.

+ +

Return null if your renderer cannot handle the given inline element - the next-highest priority renderer will then be given a chance to render it.

+ +

Designating Inline Renderers

+ +

When registering your render, you must tell the Environment which inline element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the inline class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addInlineRenderer('League\CommonMark\Inline\Element\Link', new MyCustomLinkRenderer());
+
+ +

Example

+ +

Here’s a custom renderer which puts a special class on links to external sites:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+use League\CommonMark\HtmlElement;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+    private $host;
+
+    public function __construct($host)
+    {
+        $this->host = $host;
+    }
+
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . get_class($inline));
+        }
+
+        $attrs = array();
+
+        $attrs['href'] = $htmlRenderer->escape($inline->getUrl(), true);
+
+        if (isset($inline->attributes['title'])) {
+            $attrs['title'] = $htmlRenderer->escape($inline->data['title'], true);
+        }
+
+        if ($this->isExternalUrl($inline->getUrl())) {
+            $attrs['class'] = 'external-link';
+        }
+
+        return new HtmlElement('a', $attrs, $htmlRenderer->renderInlines($inline->children()));
+    }
+
+    private function isExternalUrl($url)
+    {
+        return parse_url($url, PHP_URL_HOST) !== $this->host;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineRenderer(Link::class, new MyCustomLinkRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/customization/overview/index.html b/1.4/customization/overview/index.html new file mode 100644 index 0000000000..9c5b39bf6c --- /dev/null +++ b/1.4/customization/overview/index.html @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders you need
  2. +
  3. Set custom configuration options within the Environment
  4. +
  5. Instantiate a DocParser and HtmlRenderer using that Environment
  6. +
  7. Use the DocParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  8. +
  9. Use the HtmlRenderer to convert the AST Document into HTML
  10. +
+ +

CommonMarkConverter handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->setConfig([
+    'html_input' => 'strip',
+]);
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renders convert the parsed blocks/inlines from the AST representation into HTML. There are two types of renderers:

+ + + +

When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you +to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/autolinks/index.html b/1.4/extensions/autolinks/index.html new file mode 100644 index 0000000000..7f4853e2c5 --- /dev/null +++ b/1.4/extensions/autolinks/index.html @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

It also provides a parser to autolink @mentions to Twitter, GitHub, or any custom service you wish, though this is disabled by default.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

This extension also provides functionality to automatically link “mentions” like @colinodell to Twitter, GitHub, or any other site of your choice!

+ +

For Twitter:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\InlineMentionParser;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(InlineMentionParser::createTwitterHandleParser());
+
+// TODO: Instantiate your converter and convert some Markdown
+
+ +

For GitHub:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\InlineMentionParser;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(InlineMentionParser::createGithubHandleParser());
+
+// TODO: Instantiate your converter and convert some Markdown
+
+ +

Or configure your own custom one:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\InlineMentionParser;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new InlineMentionParser('https://www.example.com/users/%s/profile'));
+
+// TODO: Instantiate your converter and convert some Markdown
+
+ +

When creating your own, you can provide two parameters to the constructor:

+ + + +

Note that @mention-style linking doesn’t actually require you to add the extension - just the InlineParser of your choice.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/commonmark/index.html b/1.4/extensions/commonmark/index.html new file mode 100644 index 0000000000..0b86bc85f1 --- /dev/null +++ b/1.4/extensions/commonmark/index.html @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically included for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Or if you call the Environment::createCommonMarkEnvironment() helper:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\CommonMarkCoreExtension;
+use League\CommonMark\HtmlRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/disallowed-raw-html/index.html b/1.4/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..62de08f7fc --- /dev/null +++ b/1.4/extensions/disallowed-raw-html/index.html @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically filters certain HTML tags when rendering output, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('I cannot change the page <title>anymore</title>');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/external-links/index.html b/1.4/extensions/external-links/index.html new file mode 100644 index 0000000000..8411a835f8 --- /dev/null +++ b/1.4/extensions/external-links/index.html @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Set your configuration
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\HtmlElement;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+
+    /**
+     * @param Link                     $inline
+     * @param ElementRendererInterface $htmlRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . \get_class($inline));
+        }
+
+        if ($inline->getData('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to add a custom icon by targeting the html_class given in the configuration:

+ +
$config = [
+    'external_link' => [
+        'html_class' => 'external',
+    ],
+];
+
+ +
/**
+ * Custom SVG Icon.
+ */
+a[target="_blank"]::after,
+a.external::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link External (https://iconify.design/icon-sets/octicon/link-external.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 12 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M11 10h1v3c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1V3c0-.55.45-1 1-1h3v1H1v10h10v-3zM6 2l2.25 2.25L5 7.5 6.5 9l3.25-3.25L12 8V2H6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/github-flavored-markdown/index.html b/1.4/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..32da09ab82 --- /dev/null +++ b/1.4/extensions/github-flavored-markdown/index.html @@ -0,0 +1,422 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/heading-permalinks/index.html b/1.4/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..32d81b820a --- /dev/null +++ b/1.4/extensions/heading-permalinks/index.html @@ -0,0 +1,545 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Set your configuration
+$config = [
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'user-content',
+        'inner_contents' => HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS,
+        'insert' => 'before',
+        'title' => 'Permalink',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

inner_contents

+ +

This controls the HTML you want to appear inside of the generated <a> tag. Usually this would be something you’d style as some kind of link icon.

+ +

By default, we provide an embedded Octicon link SVG, but you can replace this with any custom HTML you wish.

+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'inner_contents' => '¶',
+        'insert' => 'after',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the icon just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing inner_contents:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'inner_contents' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/inlines-only/index.html b/1.4/extensions/inlines-only/index.html new file mode 100644 index 0000000000..5a2a2379fc --- /dev/null +++ b/1.4/extensions/inlines-only/index.html @@ -0,0 +1,405 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+
+// Create a new, empty environment
+$environment = new Environment();
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/overview/index.html b/1.4/extensions/overview/index.html new file mode 100644 index 0000000000..2ea452b9b9 --- /dev/null +++ b/1.4/extensions/overview/index.html @@ -0,0 +1,510 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/smart-punctuation/index.html b/1.4/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..1a1352c3d9 --- /dev/null +++ b/1.4/extensions/smart-punctuation/index.html @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Set your configuration
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/strikethrough/index.html b/1.4/extensions/strikethrough/index.html new file mode 100644 index 0000000000..c36a080d25 --- /dev/null +++ b/1.4/extensions/strikethrough/index.html @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/table-of-contents/index.html b/1.4/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..f87895d15a --- /dev/null +++ b/1.4/extensions/table-of-contents/index.html @@ -0,0 +1,557 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Set your configuration
+$config = [
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/tables/index.html b/1.4/extensions/tables/index.html new file mode 100644 index 0000000000..c1400daca1 --- /dev/null +++ b/1.4/extensions/tables/index.html @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Table\TableExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/extensions/task-lists/index.html b/1.4/extensions/task-lists/index.html new file mode 100644 index 0000000000..2a314e0db3 --- /dev/null +++ b/1.4/extensions/task-lists/index.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convertToHtml($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/index.html b/1.4/index.html new file mode 100644 index 0000000000..8ce0fb8902 --- /dev/null +++ b/1.4/index.html @@ -0,0 +1,411 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/installation/index.html b/1.4/installation/index.html new file mode 100644 index 0000000000..ef74240f2c --- /dev/null +++ b/1.4/installation/index.html @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +

In your project root just run:

+ +
composer require league/commonmark:^1.4
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^1.4. This is equivalent to >=1.4 <2.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/security/index.html b/1.4/security/index.html new file mode 100644 index 0000000000..ef6cfd6c0d --- /dev/null +++ b/1.4/security/index.html @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.4/upgrading/index.html b/1.4/upgrading/index.html new file mode 100644 index 0000000000..77f283aa57 --- /dev/null +++ b/1.4/upgrading/index.html @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.3 - 1.4 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.4. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 1.3 to 1.4

+ +

Changes

+ +

Rendering block/inline subclasses

+ +

Imagine you have the following inline elements:

+ +
class Link extends AbstractWebResource { } // This is the is the standard CommonMark "Link" element
+
+class ShortLink extends Link { } // A custom inline node type you created which extends "Link"
+
+class BitlyLink extends ShortLink { } // Another custom inline node type you created
+
+ +

Prior to 1.4, you’d have to manually register corresponding inline renderers for each one:

+ +
/** @var \League\CommonMark\Environment $environment */
+$environment->addInlineRenderer(Link::class, new LinkRenderer()); // this line is usually automatically done for you
+$environment->addInlineRenderer(ShortLink::class, new LinkRenderer()); // register for custom node type; required before 1.4
+$environment->addInlineRenderer(BitlyLink::class, new LinkRenderer()); // register for custom node type; required before 1.4
+
+ +

But in 1.4 onwards, you no longer need to manually register that LinkRenderer for subclasses (like ShortLink and BitlyLink in the example above) - if the Environment can’t find a registered renderer for that specific block/inline node type, we’ll automatically check if the node’s parent classes have a registered renderer and use that instead.

+ +

Previously, if you forgot to register those renderers, the rendering process would fail with a RuntimeException like “Unable to find corresponding renderer”.

+ +

ListBlock::TYPE_ constant values

+ +

The two constants in the ListBlock class no longer contain title-cased values - the first character is now lowercased. Ideally, you should be referencing the constants, but if you were instead hard-coding these values in your application, you may need to adjust those hard-coded strings.

+ +

Deprecations

+ +

Several things have been deprecated in 1.4 - they’ll continue to work, but consider using alternatives to make your code easier to upgrade to 2.0 when these deprecated things are removed.

+ +

ListBlock::TYPE_UNORDERED constant

+ +

The ListBlock::TYPE_UNORDERED constant has been deprecated, use ListBlock::TYPE_BULLET instead.

+ +

bin/commonmark command

+ +

This command has been buggy to test and is relatively unpopular, so this will be removed in 2.0. If you need this type of functionality, consider writing your own script with a Converter/Environment configured exactly how you want it.

+ +

ArrayCollection methods

+ +

This class has several unused methods, or methods with an existing alternative:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Method NameAlternative
add($value)$collection[] = $value
set($key, $value)$collection[$key] = $value
get($key)$collection[$key]
remove($key)unset($collection[$key])
isEmpty()count($collection) === 0
contains($value)in_array($value, $collection->toArray(), true)
indexOf($value)array_search($value, $collection->toArray(), true)
containsKey($key)isset($collection[$key])
replaceWith()(none provided)
removeGaps()(none provided)
+ +

Converter and ConverterInterface

+ +

The Converter class has been deprecated - switch to using CommonMarkConverter instead.

+ +

The ConverterInterface has been deprecated - switch to using MarkdownConverterInterface instead.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/basic-usage/index.html b/1.5/basic-usage/index.html new file mode 100644 index 0000000000..8b0143d3f8 --- /dev/null +++ b/1.5/basic-usage/index.html @@ -0,0 +1,420 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

Additional customization is also possible, and we have many handy extensions to enable additional syntax and features.

+ +

Supported Character Encodings

+ +

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.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/changelog/index.html b/1.5/changelog/index.html new file mode 100644 index 0000000000..966814c79c --- /dev/null +++ b/1.5/changelog/index.html @@ -0,0 +1,1068 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 1.x releases are shown below. See the full list of releases for the complete changelog.

+ +

1.6.7 - 2022-01-13

+ +

Changed

+ + + +

1.6.6 - 2021-07-17

+ +

Fixed

+ + + +

1.6.5 - 2021-06-26

+ +

Changed

+ + + +

Fixed

+ + + +

1.6.4 - 2021-06-19

+ +

Changed

+ + + +

1.6.3 - 2021-06-19

+ +

Fixed

+ + + +

1.6.2 - 2021-05-12

+ +

Fixed

+ + + +

1.6.1 - 2021-05-08

+ +

Fixed

+ + + +

1.6.0 - 2021-05-01

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

Fixed

+ + + +

1.5.8 - 2021-03-28

+ +

Fixed

+ + + +

1.5.7 - 2020-10-31

+ +

Fixed

+ + + +

1.5.6 - 2020-10-17

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.5 - 2020-09-13

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.4 - 2020-08-18

+ +

Fixed

+ + + +

1.5.3 - 2020-07-19

+ +

Fixed

+ + + +

1.5.2 - 2020-07-19

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.1 - 2020-06-27

+ +

Fixed

+ + + +

1.5.0 - 2020-06-21

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.4.3 - 2020-05-04

+ +

Fixed

+ + + +

1.4.2 - 2020-04-24

+ +

Fixed

+ + + +

1.4.1 - 2020-04-20

+ +

Fixed

+ + + +

1.4.0 - 2020-04-18

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.3.4 - 2020-04-13

+ +

Fixed

+ + + +

1.3.3 - 2020-04-05

+ +

Fixed

+ + + +

1.3.2 - 2020-03-25

+ +

Fixed

+ + + +

1.3.1 - 2020-02-28

+ +

Fixed

+ + + +

1.3.0 - 2020-02-09

+ +

ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.

+ +

Added

+ + + +

Changed

+ + + +

1.2.2 - 2020-01-16

+ +

This release contains the same changes as 1.1.3:

+ +

Fixed

+ + + +

1.1.3 - 2020-01-16

+ +

Fixed

+ + + +

1.2.1 - 2020-01-15

+ +

Changed

+ + + +

1.2.0 - 2020-01-09

+ +

Changed

+ + + +

1.1.2 - 2019-12-10

+ +

Fixed

+ + + +

1.1.1 - 2019-11-11

+ +

Fixed

+ + + +

1.1.0 - 2019-10-31

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.0.0 - 2019-06-29

+ +

First stable release! 🎉

+ +

No code changes have been introduced since 1.0.0-rc1

+ +

1.0.0-rc1 - 2019-06-20

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

1.0.0-beta4 - 2019-06-05

+ +

Added

+ + + +

Removed

+ + + +

1.0.0-beta3 - 2019-05-28

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta2 - 2019-05-27

+ +

This beta release fixes a couple of items that were not addressed in the previous beta.

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta1 - 2019-05-26

+ +

See the upgrading guide for additional information.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

Removed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/command-line/index.html b/1.5/command-line/index.html new file mode 100644 index 0000000000..1c0bc2bfa0 --- /dev/null +++ b/1.5/command-line/index.html @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + + + Command Line - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Command Line

+ +

This functionality has been deprecated in version 1.4 and will be removed in 2.0.

+ +

Markdown can be converted at the command line using the ./bin/commonmark script.

+ +

Usage

+ +
./bin/commonmark [OPTIONS] [FILE]
+
+ + + +

If no file is given, input will be read from STDIN.

+ +

Output will be written to STDOUT.

+ +

Examples

+ +

Converting a file named document.md

+ +
./bin/commonmark document.md
+
+ +

Converting a file and saving its output

+ +
./bin/commonmark document.md > output.html
+
+ +

Converting from STDIN

+ +
echo -e '# Hello World!' | ./bin/commonmark
+
+ +

Converting from STDIN and saving the output

+ +
echo -e '# Hello World!' | ./bin/commonmark > output.html
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/configuration/index.html b/1.5/configuration/index.html new file mode 100644 index 0000000000..6c268b9560 --- /dev/null +++ b/1.5/configuration/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

You can provide an array of configuration options to the CommonMarkConverter when creating it:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter([
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'enable_em' => true,
+    'enable_strong' => true,
+    'use_asterisk' => true,
+    'use_underscore' => true,
+    'unordered_list_markers' => ['-', '*', '+'],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => INF,
+]);
+
+ +

Here’s a list of currently-supported options:

+ + + +

Additional configuration options are available for some of the available extensions - refer to their individual documentation for more details.

+ +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

The Environment also exposes three methods for managing the configuration:

+ + + +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/abstract-syntax-tree/index.html b/1.5/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..48acbb5f55 --- /dev/null +++ b/1.5/customization/abstract-syntax-tree/index.html @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Traversal

+ +

The following methods can be used to traverse the AST:

+ + + +

Iteration / Walking the Tree

+ +

If you’d like to iterate through all the nodes, use the walker() method to obtain an instance of NodeWalker. This will walk through the entire tree, emitting NodeWalkerEvents along the way.

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'I am ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

This walker doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes.

+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/block-parsing/index.html b/1.5/customization/block-parsing/index.html new file mode 100644 index 0000000000..2ee5659365 --- /dev/null +++ b/1.5/customization/block-parsing/index.html @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

Block parsers should implement BlockParserInterface and implement the following method:

+ +

parse()

+ +
public function parse(ContextInterface $context, Cursor $cursor): bool;
+
+ +

When parsing a new line, the DocParser iterates through all registered block parsers and calls their parse() method. Each parser must determine whether it can handle the given line; if so, it should parse the given block and return true.

+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the line will be parsed as text.

+ +

Returning true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of syntax indicating the block start
  2. +
  3. Add the parsed block via $context->addBlock()
  4. +
+ +

Tips

+ + + +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

Block elements also play a role during the parsing process as they tell the underlying engine how to handle subsequent blocks that are found.

+ +

AbstractBlockElement Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
canContain(...)Tell the engine whether a subsequent block can be added as a child of yours
isCode()Returns whether this block represents an extra-greedy <code> block
matchesNextLine(...)Returns whether this block continues onto the next line (some blocks are multi-line)
shouldLastLineBeBlank()Returns whether the last line should be blank (primarily used by ListItem elements)
finalize(...)Finalizes the block after all child items have been added, thus marking it as closed for modification
+ +

For examples on how these methods are used, see the core block element classes included with this library.

+ +

AbstractStringContainerBlock

+ +

If your element can contain strings of text, you should extend AbstractStringContainerBlock instead of AbstractBlock. This provides some additional methods needed to manage that inner text:

+ + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
handleRemainingContents(...)This is called when a block has been created but some other text still exists on that line
addLine(...)Adds the given line of text to the block element
getStringContent()Returns the strings contained with that block element
+ +

InlineContainerInterface

+ +

If the text contained by your block should be parsed for inline elements, you should also implement the InlineContainerInterface. This doesn’t add any new methods but does signal to the engine that inline parsing is required.

+ +

Multi-line Code Blocks

+ +

If you have a block which spans multiple lines and doesn’t contain any child blocks, consider having isCode() return true. Code blocks have a special feature which enables “greedy parsing” - once it first parses your block, the engine will assume that most of the subsequent lines of Markdown belong to your block - it won’t try using any other parsers until your parser’s matchesNextLine() method returns false, indicating that we’ve reached the end of that code block.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/block-rendering/index.html b/1.5/customization/block-rendering/index.html new file mode 100644 index 0000000000..f546797f7b --- /dev/null +++ b/1.5/customization/block-rendering/index.html @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + Block Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Block Rendering

+ +

Block renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement BlockRendererInterface and its render() method:

+ +

render()

+ +
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false);
+
+ +

The HtmlRenderer will call this method whenever a supported block element is encountered in the AST being rendered.

+ +

If the method can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the block and any of its contents. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Block Renderers

+ +

When registering your renderer, you must tell the Environment which block element class your renderer should handle. For example:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the block class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addBlockRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple block types:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Block\Element\IndentedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addBlockRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addBlockRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Node\Block\AbstractBlock;
+use League\CommonMark\Renderer\Block\BlockRendererInterface;
+use League\CommonMark\Renderer\ElementRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements BlockRendererInterface
+{
+    public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addBlockRenderer('League\CommonMark\Block\Element\ThematicBreak', new TextDividerRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/cursor/index.html b/1.5/customization/cursor/index.html new file mode 100644 index 0000000000..95b4e29be0 --- /dev/null +++ b/1.5/customization/cursor/index.html @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter()Returns the character at the current position
getCharacter(int $index)Returns the character at the given absolute position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/delimiter-processing/index.html b/1.5/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..ea10dc9bb4 --- /dev/null +++ b/1.5/customization/delimiter-processing/index.html @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse);
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/document-processing/index.html b/1.5/customization/document-processing/index.html new file mode 100644 index 0000000000..2bc8e62835 --- /dev/null +++ b/1.5/customization/document-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/1.5/customization/environment/index.html b/1.5/customization/environment/index.html new file mode 100644 index 0000000000..fbe3010301 --- /dev/null +++ b/1.5/customization/environment/index.html @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

A pre-configured Environment can be obtained like this:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+ +

All of the core renders, parsers, etc. needed to implement the CommonMark spec will be pre-registered and ready to go.

+ +

You can customize this default Environment (or even a new, empty one) using any of the methods below (from the ConfigurableEnvironmentInterface interface).

+ +

mergeConfig()

+ +
public function mergeConfig(array $config = []);
+
+ +

Merges the given configuration settings into any existing ones.

+ +

setConfig()

+ +
public function setConfig(array $config = []);
+
+ +

Completely replaces the previous configuration settings with the new $config you provide.

+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. This is typically how you’d integrate third-party extensions with this library.

+ +

addBlockParser()

+ +
public function addBlockParser(BlockParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addBlockRenderer()

+ +
public function addBlockRenderer(string $blockClass, BlockRendererInterface $blockRenderer, int $priority = 0);
+
+ +

Registers a BlockRendererInterface to handle a specific type of block ($blockClass) with the given priority (a higher number will be executed earlier).

+ +

See Block Rendering for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addInlineRenderer()

+ +
public function addInlineRenderer(string $inlineClass, InlineRendererInterface $renderer, int $priority = 0);
+
+ +

Registers an InlineRendererInterface to handle a specific type of inline ($inlineClass) with the given priority (a higher number will be executed earlier). +A single renderer can handle multiple inline classes, but you must register it separately for each type. (The same renderer instance can be re-used if desired.)

+ +

See Inline Rendering for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/event-dispatcher/index.html b/1.5/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..971c12eca9 --- /dev/null +++ b/1.5/customization/event-dispatcher/index.html @@ -0,0 +1,531 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code. If you’re familiar with Symfony’s EventDispatcher or PSR-14 then this should be very familiar to you.

+ +

Event Class

+ +

All events must extend from the AbstractEvent class:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - an instance of AbstractEvent to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Inline\Element\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event)
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data['attributes']['class'] = 'external-link';
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfig('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = Environment::createCommonMarkEnvironment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/extensions/index.html b/1.5/customization/extensions/index.html new file mode 100644 index 0000000000..e3878c05e9 --- /dev/null +++ b/1.5/customization/extensions/index.html @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment)
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new EmojiExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/inline-parsing/index.html b/1.5/customization/inline-parsing/index.html new file mode 100644 index 0000000000..659b92214c --- /dev/null +++ b/1.5/customization/inline-parsing/index.html @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getCharacters()

+ +

This method should return an array of single characters which the inline parser engine should stop on. When it does find a match in the current line the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has stopped at a matching character; and,
  2. +
  3. No other inline parsers have successfully parsed the character
  4. +
+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line/character for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the character will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return ['@'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+        // Save the cursor state in case we need to rewind and bail
+        $previousState = $cursor->saveState();
+        // Advance past the @ symbol to keep parsing simpler
+        $cursor->advance();
+        // Parse the handle
+        $handle = $cursor->match('/^[A-Za-z0-9_]{1,15}(?!\w)/');
+        if (empty($handle)) {
+            // Regex failed to match; this isn't a valid Twitter handle
+            $cursor->restoreState($previousState);
+            return false;
+        }
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Image;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return [':'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // The next character must be a paren; if not, then bail
+        // We use peek() to quickly check without affecting the cursor
+        $nextChar = $cursor->peek();
+        if ($nextChar !== '(' && $nextChar !== ')') {
+            return false;
+        }
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($nextChar === ')') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($nextChar === '(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/inline-rendering/index.html b/1.5/customization/inline-rendering/index.html new file mode 100644 index 0000000000..2131ef611c --- /dev/null +++ b/1.5/customization/inline-rendering/index.html @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + Inline Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Inline Rendering

+ +

Inline renderers are responsible for converting the parsed inline elements into their HTML representation.

+ +

All inline renderers should implement InlineRendererInterface and its render() method:

+ +

render()

+ +

Block elements are responsible for calling $htmlRenderer->renderInlines() if they contain inline elements. This in turns causes the HtmlRenderer to call this render() method whenever a supported inline element is encountered.

+ +

If the method can only handle certain inline types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the entire inline and any contents. This can be an HtmlElement object (preferred; castable to a string) or a string of raw HTML.

+ +

You are responsible for handling any escaping that may be necessary.

+ +

Return null if your renderer cannot handle the given inline element - the next-highest priority renderer will then be given a chance to render it.

+ +

Designating Inline Renderers

+ +

When registering your render, you must tell the Environment which inline element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the inline class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addInlineRenderer('League\CommonMark\Inline\Element\Link', new MyCustomLinkRenderer());
+
+ +

Example

+ +

Here’s a custom renderer which puts a special class on links to external sites:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+use League\CommonMark\HtmlElement;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+    private $host;
+
+    public function __construct($host)
+    {
+        $this->host = $host;
+    }
+
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . get_class($inline));
+        }
+
+        $attrs = array();
+
+        $attrs['href'] = $htmlRenderer->escape($inline->getUrl(), true);
+
+        if (isset($inline->attributes['title'])) {
+            $attrs['title'] = $htmlRenderer->escape($inline->data['title'], true);
+        }
+
+        if ($this->isExternalUrl($inline->getUrl())) {
+            $attrs['class'] = 'external-link';
+        }
+
+        return new HtmlElement('a', $attrs, $htmlRenderer->renderInlines($inline->children()));
+    }
+
+    private function isExternalUrl($url)
+    {
+        return parse_url($url, PHP_URL_HOST) !== $this->host;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineRenderer(Link::class, new MyCustomLinkRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/customization/overview/index.html b/1.5/customization/overview/index.html new file mode 100644 index 0000000000..21c25a6a50 --- /dev/null +++ b/1.5/customization/overview/index.html @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders you need
  2. +
  3. Set custom configuration options within the Environment
  4. +
  5. Instantiate a DocParser and HtmlRenderer using that Environment
  6. +
  7. Use the DocParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  8. +
  9. Use the HtmlRenderer to convert the AST Document into HTML
  10. +
+ +

CommonMarkConverter handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->setConfig([
+    'html_input' => 'strip',
+]);
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renders convert the parsed blocks/inlines from the AST representation into HTML. There are two types of renderers:

+ + + +

When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you +to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/attributes/index.html b/1.5/extensions/attributes/index.html new file mode 100644 index 0000000000..0c20b05402 --- /dev/null +++ b/1.5/extensions/attributes/index.html @@ -0,0 +1,442 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+{#id .class}
+## Header
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the extension
+$environment->addExtension(new AttributesExtension());
+
+// Set your configuration if needed
+$config = [
+    // ...
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/autolinks/index.html b/1.5/extensions/autolinks/index.html new file mode 100644 index 0000000000..b49ca68d2f --- /dev/null +++ b/1.5/extensions/autolinks/index.html @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a separate Mention extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/commonmark/index.html b/1.5/extensions/commonmark/index.html new file mode 100644 index 0000000000..d31bf9c63c --- /dev/null +++ b/1.5/extensions/commonmark/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically included for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Or if you call the Environment::createCommonMarkEnvironment() helper:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\CommonMarkCoreExtension;
+use League\CommonMark\HtmlRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/disallowed-raw-html/index.html b/1.5/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..8e19894271 --- /dev/null +++ b/1.5/extensions/disallowed-raw-html/index.html @@ -0,0 +1,437 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically filters certain HTML tags when rendering output, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('I cannot change the page <title>anymore</title>');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/external-links/index.html b/1.5/extensions/external-links/index.html new file mode 100644 index 0000000000..9e935aa17b --- /dev/null +++ b/1.5/extensions/external-links/index.html @@ -0,0 +1,544 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Set your configuration
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +

+use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\HtmlElement;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+
+    /**
+     * @param Link                     $inline
+     * @param ElementRendererInterface $htmlRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . \get_class($inline));
+        }
+
+        if ($inline->getData('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to add a custom icon by targeting the html_class given in the configuration:

+ +
$config = [
+    'external_link' => [
+        'html_class' => 'external',
+    ],
+];
+
+ +
/**
+ * Custom SVG Icon.
+ */
+a[target="_blank"]::after,
+a.external::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link External (https://iconify.design/icon-sets/octicon/link-external.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 12 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M11 10h1v3c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1V3c0-.55.45-1 1-1h3v1H1v10h10v-3zM6 2l2.25 2.25L5 7.5 6.5 9l3.25-3.25L12 8V2H6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/footnotes/index.html b/1.5/extensions/footnotes/index.html new file mode 100644 index 0000000000..418660a9a0 --- /dev/null +++ b/1.5/extensions/footnotes/index.html @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1">&#8617;</a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Set your configuration
+$config = [
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/github-flavored-markdown/index.html b/1.5/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..807e8b8570 --- /dev/null +++ b/1.5/extensions/github-flavored-markdown/index.html @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/heading-permalinks/index.html b/1.5/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..f3465d4455 --- /dev/null +++ b/1.5/extensions/heading-permalinks/index.html @@ -0,0 +1,620 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\Normalizer\SlugNormalizer;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Set your configuration
+$config = [
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'user-content',
+        'insert' => 'before',
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'slug_normalizer' => new SlugNormalizer(),
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

inner_contents (deprecated since 1.5.0)

+ +

This controls the HTML you want to appear inside of the generated <a> tag. Usually this would be something you would +style as some kind of link icon, but you can replace this with any custom HTML you wish.

+ +

This option was deprecated in 1.5.0 and will be removed in 2.0.0. Use the symbol option instead.

+ +

This option has no default value and if one is provided, a deprecation warning will be triggered and the symbol +config option below will be ignored completely.

+ +

See the Upgrade Guide for more information.

+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

slug_normalizer

+ +

“Slugs” are the strings used within the href, name, and id attributes to identify a particular permalink. +By default, this extension will generate slugs based on the contents of the heading, just like GitHub-Flavored Markdown does.

+ +

You can change the string that is used as the “slug” by setting the slug_normalizer option to any class that implements TextNormalizerInterface.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'heading_permalink' => [
+        // ... other options here ...
+        'slug_normalizer' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'heading_permalink' => [
+        // ... other options here ...
+        'slug_normalizer' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/inlines-only/index.html b/1.5/extensions/inlines-only/index.html new file mode 100644 index 0000000000..6acef32d2f --- /dev/null +++ b/1.5/extensions/inlines-only/index.html @@ -0,0 +1,417 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+
+// Create a new, empty environment
+$environment = new Environment();
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/mentions/index.html b/1.5/extensions/mentions/index.html new file mode 100644 index 0000000000..9f5ebf40a1 --- /dev/null +++ b/1.5/extensions/mentions/index.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which symbol you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting symbol, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Mention\MentionExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go.
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Set your configuration.
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'symbol'    => '@',
+            'regex'     => '/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)/',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'symbol'    => '#',
+            'regex'     => '/^\d+/',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same symbol, the last one registered will
+        // always take precedence.
+        'twitter_handle' => [
+            'symbol'    => '@',
+            'regex'     => '/^[A-Za-z0-9_]{1,15}(?!\w)/',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://twitter.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Symbol └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the symbol (in this case, @). You can use any symbol, regex pattern, or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go.
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Set your configuration.
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'symbol'    => '@',
+            'regex'     => '/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)/',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'symbol'    => '#',
+            'regex'     => '/^\d+/',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'symbol'    => '#',
+            'regex'     => '/^\d+/',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Mention\MentionExtension;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Set your configuration.
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'symbol'    => '@',
+            'regex'     => '/^[a-z0-9]+/i',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/overview/index.html b/1.5/extensions/overview/index.html new file mode 100644 index 0000000000..f71e795028 --- /dev/null +++ b/1.5/extensions/overview/index.html @@ -0,0 +1,540 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new CommonMarkConverter([], $environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/smart-punctuation/index.html b/1.5/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..f5ec82cdae --- /dev/null +++ b/1.5/extensions/smart-punctuation/index.html @@ -0,0 +1,437 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Set your configuration
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/strikethrough/index.html b/1.5/extensions/strikethrough/index.html new file mode 100644 index 0000000000..701d677779 --- /dev/null +++ b/1.5/extensions/strikethrough/index.html @@ -0,0 +1,419 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/table-of-contents/index.html b/1.5/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..bfcb36e0fd --- /dev/null +++ b/1.5/extensions/table-of-contents/index.html @@ -0,0 +1,575 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Set your configuration
+$config = [
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/tables/index.html b/1.5/extensions/tables/index.html new file mode 100644 index 0000000000..6825b7e6a0 --- /dev/null +++ b/1.5/extensions/tables/index.html @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\Table\TableExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter($config, $environment);
+echo $converter->convertToHtml('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/extensions/task-lists/index.html b/1.5/extensions/task-lists/index.html new file mode 100644 index 0000000000..f32c4e60bc --- /dev/null +++ b/1.5/extensions/task-lists/index.html @@ -0,0 +1,428 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new CommonMarkConverter([], $environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convertToHtml($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/index.html b/1.5/index.html new file mode 100644 index 0000000000..aa44595fdd --- /dev/null +++ b/1.5/index.html @@ -0,0 +1,423 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/installation/index.html b/1.5/installation/index.html new file mode 100644 index 0000000000..97c142c88f --- /dev/null +++ b/1.5/installation/index.html @@ -0,0 +1,400 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +

In your project root just run:

+ +
composer require league/commonmark:^1.5
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^1.5. This is equivalent to >=1.5 <2.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/security/index.html b/1.5/security/index.html new file mode 100644 index 0000000000..c968d4c50b --- /dev/null +++ b/1.5/security/index.html @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.5/upgrading/index.html b/1.5/upgrading/index.html new file mode 100644 index 0000000000..b0c8569ec8 --- /dev/null +++ b/1.5/upgrading/index.html @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.4 - 1.5 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.5. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 1.4 to 1.5

+ +

Changes

+ +

Reference labels are no longer auto-normalized within the Reference constructor. Normalization only occurs within the ReferenceMap.

+ +

Deprecations

+ +

Reference::normalizeReference() has been deprecated. Use TextNormalizer::normalize() instead.

+ +

The InlineMentionParser has been deprecated. Use MentionParser instead.

+ + + +

The following two classes have been deprecated in favor of more-generic text normalizers:

+ + + + + + + + + + + + + + + + + + +
Old ClassNew Class
Extension\HeadingPermalink\Slug\DefaultSlugGeneratorNormalizer\SlugNormalizer
Extension\HeadingPermalink\Slug\SlugGeneratorInterfaceNormalizer\TextNormalizerInterface
+ +

The method signatures of these classes are slightly different:

+ +
public function createSlug(string $input): string;
+
+ +

To:

+ +
public function normalize(string $input, $context = null): string;
+
+ +

heading_permalink/inner_contents configuration option

+ +

Prior to 1.5.0, this configuration option’s default value was an embedded Octicon link SVG, +but any custom HTML could be provided.

+ +

If you wish to restore the previous functionality, you may supply inner_contents with the original default value by +using the constant HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS (which is now also deprecated):

+ +
use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+
+$config = [
+    'heading_permalink' => [
+        'inner_contents' => HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS,
+    ],
+];
+
+ +

This configuration option will be removed in 2.0.0 in favor of the new heading_permalink/symbol configuration +option. Moving forward, you will need to supply your own custom icon via CSS by removing the default symbol value:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/basic-usage/index.html b/1.6/basic-usage/index.html new file mode 100644 index 0000000000..cd02be8213 --- /dev/null +++ b/1.6/basic-usage/index.html @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or you can use the generic MarkdownConverter class to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

Additional customization is also possible, and we have many handy extensions to enable additional syntax and features.

+ +

Supported Character Encodings

+ +

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.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/changelog/index.html b/1.6/changelog/index.html new file mode 100644 index 0000000000..42ece70e95 --- /dev/null +++ b/1.6/changelog/index.html @@ -0,0 +1,1072 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 1.x releases are shown below. See the full list of releases for the complete changelog.

+ +

1.6.7 - 2022-01-13

+ +

Changed

+ + + +

1.6.6 - 2021-07-17

+ +

Fixed

+ + + +

1.6.5 - 2021-06-26

+ +

Changed

+ + + +

Fixed

+ + + +

1.6.4 - 2021-06-19

+ +

Changed

+ + + +

1.6.3 - 2021-06-19

+ +

Fixed

+ + + +

1.6.2 - 2021-05-12

+ +

Fixed

+ + + +

1.6.1 - 2021-05-08

+ +

Fixed

+ + + +

1.6.0 - 2021-05-01

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

Fixed

+ + + +

1.5.8 - 2021-03-28

+ +

Fixed

+ + + +

1.5.7 - 2020-10-31

+ +

Fixed

+ + + +

1.5.6 - 2020-10-17

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.5 - 2020-09-13

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.4 - 2020-08-18

+ +

Fixed

+ + + +

1.5.3 - 2020-07-19

+ +

Fixed

+ + + +

1.5.2 - 2020-07-19

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.1 - 2020-06-27

+ +

Fixed

+ + + +

1.5.0 - 2020-06-21

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.4.3 - 2020-05-04

+ +

Fixed

+ + + +

1.4.2 - 2020-04-24

+ +

Fixed

+ + + +

1.4.1 - 2020-04-20

+ +

Fixed

+ + + +

1.4.0 - 2020-04-18

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.3.4 - 2020-04-13

+ +

Fixed

+ + + +

1.3.3 - 2020-04-05

+ +

Fixed

+ + + +

1.3.2 - 2020-03-25

+ +

Fixed

+ + + +

1.3.1 - 2020-02-28

+ +

Fixed

+ + + +

1.3.0 - 2020-02-09

+ +

ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.

+ +

Added

+ + + +

Changed

+ + + +

1.2.2 - 2020-01-16

+ +

This release contains the same changes as 1.1.3:

+ +

Fixed

+ + + +

1.1.3 - 2020-01-16

+ +

Fixed

+ + + +

1.2.1 - 2020-01-15

+ +

Changed

+ + + +

1.2.0 - 2020-01-09

+ +

Changed

+ + + +

1.1.2 - 2019-12-10

+ +

Fixed

+ + + +

1.1.1 - 2019-11-11

+ +

Fixed

+ + + +

1.1.0 - 2019-10-31

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.0.0 - 2019-06-29

+ +

First stable release! 🎉

+ +

No code changes have been introduced since 1.0.0-rc1

+ +

1.0.0-rc1 - 2019-06-20

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

1.0.0-beta4 - 2019-06-05

+ +

Added

+ + + +

Removed

+ + + +

1.0.0-beta3 - 2019-05-28

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta2 - 2019-05-27

+ +

This beta release fixes a couple of items that were not addressed in the previous beta.

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta1 - 2019-05-26

+ +

See the upgrading guide for additional information.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

Removed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/command-line/index.html b/1.6/command-line/index.html new file mode 100644 index 0000000000..f6fee60710 --- /dev/null +++ b/1.6/command-line/index.html @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + Command Line - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Command Line

+ +

This functionality has been deprecated in version 1.4 and will be removed in 2.0.

+ +

Markdown can be converted at the command line using the ./bin/commonmark script.

+ +

Usage

+ +
./bin/commonmark [OPTIONS] [FILE]
+
+ + + +

If no file is given, input will be read from STDIN.

+ +

Output will be written to STDOUT.

+ +

Examples

+ +

Converting a file named document.md

+ +
./bin/commonmark document.md
+
+ +

Converting a file and saving its output

+ +
./bin/commonmark document.md > output.html
+
+ +

Converting from STDIN

+ +
echo -e '# Hello World!' | ./bin/commonmark
+
+ +

Converting from STDIN and saving the output

+ +
echo -e '# Hello World!' | ./bin/commonmark > output.html
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/configuration/index.html b/1.6/configuration/index.html new file mode 100644 index 0000000000..1d31b9d10f --- /dev/null +++ b/1.6/configuration/index.html @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the CommonMarkConverter when creating it:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s mergeConfig() method instead:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Here's where we set the configuration array:
+$environment->mergeConfig($config);
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of currently-supported options:

+ + + +

Additional configuration options are available for some of the available extensions - refer to their individual documentation for more details.

+ +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

The Environment also exposes two methods for managing the configuration:

+ + + +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/abstract-syntax-tree/index.html b/1.6/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..c06737812f --- /dev/null +++ b/1.6/customization/abstract-syntax-tree/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Traversal

+ +

The following methods can be used to traverse the AST:

+ + + +

Iteration / Walking the Tree

+ +

If you’d like to iterate through all the nodes, use the walker() method to obtain an instance of NodeWalker. This will walk through the entire tree, emitting NodeWalkerEvents along the way.

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'I am ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

This walker doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes.

+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/block-parsing/index.html b/1.6/customization/block-parsing/index.html new file mode 100644 index 0000000000..09784d4da8 --- /dev/null +++ b/1.6/customization/block-parsing/index.html @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

Block parsers should implement BlockParserInterface and implement the following method:

+ +

parse()

+ +
public function parse(ContextInterface $context, Cursor $cursor): bool;
+
+ +

When parsing a new line, the DocParser iterates through all registered block parsers and calls their parse() method. Each parser must determine whether it can handle the given line; if so, it should parse the given block and return true.

+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the line will be parsed as text.

+ +

Returning true tells the engine that you’ve successfully parsed the block at the given position. It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of syntax indicating the block start
  2. +
  3. Add the parsed block via $context->addBlock()
  4. +
+ +

Tips

+ + + +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

Block elements also play a role during the parsing process as they tell the underlying engine how to handle subsequent blocks that are found.

+ +

AbstractBlockElement Methods

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
canContain(...)Tell the engine whether a subsequent block can be added as a child of yours
isCode()Returns whether this block represents an extra-greedy <code> block
matchesNextLine(...)Returns whether this block continues onto the next line (some blocks are multi-line)
shouldLastLineBeBlank()Returns whether the last line should be blank (primarily used by ListItem elements)
finalize(...)Finalizes the block after all child items have been added, thus marking it as closed for modification
+ +

For examples on how these methods are used, see the core block element classes included with this library.

+ +

AbstractStringContainerBlock

+ +

If your element can contain strings of text, you should extend AbstractStringContainerBlock instead of AbstractBlock. This provides some additional methods needed to manage that inner text:

+ + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
handleRemainingContents(...)This is called when a block has been created but some other text still exists on that line
addLine(...)Adds the given line of text to the block element
getStringContent()Returns the strings contained with that block element
+ +

InlineContainerInterface

+ +

If the text contained by your block should be parsed for inline elements, you should also implement the InlineContainerInterface. This doesn’t add any new methods but does signal to the engine that inline parsing is required.

+ +

Multi-line Code Blocks

+ +

If you have a block which spans multiple lines and doesn’t contain any child blocks, consider having isCode() return true. Code blocks have a special feature which enables “greedy parsing” - once it first parses your block, the engine will assume that most of the subsequent lines of Markdown belong to your block - it won’t try using any other parsers until your parser’s matchesNextLine() method returns false, indicating that we’ve reached the end of that code block.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/block-rendering/index.html b/1.6/customization/block-rendering/index.html new file mode 100644 index 0000000000..bf9c3770b8 --- /dev/null +++ b/1.6/customization/block-rendering/index.html @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + Block Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Block Rendering

+ +

Block renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement BlockRendererInterface and its render() method:

+ +

render()

+ +
public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false);
+
+ +

The HtmlRenderer will call this method whenever a supported block element is encountered in the AST being rendered.

+ +

If the method can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the block and any of its contents. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Block Renderers

+ +

When registering your renderer, you must tell the Environment which block element class your renderer should handle. For example:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the block class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addBlockRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple block types:

+ +
use League\CommonMark\Block\Element\FencedCode;
+use League\CommonMark\Block\Element\IndentedCode;
+use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addBlockRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addBlockRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Node\Block\AbstractBlock;
+use League\CommonMark\Renderer\Block\BlockRendererInterface;
+use League\CommonMark\Renderer\ElementRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements BlockRendererInterface
+{
+    public function render(AbstractBlock $block, ElementRendererInterface $htmlRenderer, bool $inTightList = false)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addBlockRenderer('League\CommonMark\Block\Element\ThematicBreak', new TextDividerRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/cursor/index.html b/1.6/customization/cursor/index.html new file mode 100644 index 0000000000..f667818bb6 --- /dev/null +++ b/1.6/customization/cursor/index.html @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter()Returns the character at the current position
getCharacter(int $index)Returns the character at the given absolute position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/delimiter-processing/index.html b/1.6/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..002a4e5b53 --- /dev/null +++ b/1.6/customization/delimiter-processing/index.html @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse);
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/environment/index.html b/1.6/customization/environment/index.html new file mode 100644 index 0000000000..88f74a1b91 --- /dev/null +++ b/1.6/customization/environment/index.html @@ -0,0 +1,481 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

A pre-configured Environment can be obtained like this:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+ +

All of the core renders, parsers, etc. needed to implement the CommonMark spec will be pre-registered and ready to go.

+ +

You can customize this default Environment (or even a new, empty one) using any of the methods below (from the ConfigurableEnvironmentInterface interface).

+ +

mergeConfig()

+ +
public function mergeConfig(array $config = []);
+
+ +

Merges the given configuration settings into any existing ones.

+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. This is typically how you’d integrate third-party extensions with this library.

+ +

addBlockParser()

+ +
public function addBlockParser(BlockParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addBlockRenderer()

+ +
public function addBlockRenderer(string $blockClass, BlockRendererInterface $blockRenderer, int $priority = 0);
+
+ +

Registers a BlockRendererInterface to handle a specific type of block ($blockClass) with the given priority (a higher number will be executed earlier).

+ +

See Block Rendering for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addInlineRenderer()

+ +
public function addInlineRenderer(string $inlineClass, InlineRendererInterface $renderer, int $priority = 0);
+
+ +

Registers an InlineRendererInterface to handle a specific type of inline ($inlineClass) with the given priority (a higher number will be executed earlier). +A single renderer can handle multiple inline classes, but you must register it separately for each type. (The same renderer instance can be re-used if desired.)

+ +

See Inline Rendering for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/event-dispatcher/index.html b/1.6/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..4ff5728d42 --- /dev/null +++ b/1.6/customization/event-dispatcher/index.html @@ -0,0 +1,535 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code. If you’re familiar with Symfony’s EventDispatcher or PSR-14 then this should be very familiar to you.

+ +

Event Class

+ +

All events must extend from the AbstractEvent class:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - an instance of AbstractEvent to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Inline\Element\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event)
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data['attributes']['class'] = 'external-link';
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfig('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = Environment::createCommonMarkEnvironment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/extensions/index.html b/1.6/customization/extensions/index.html new file mode 100644 index 0000000000..5146689ad8 --- /dev/null +++ b/1.6/customization/extensions/index.html @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment)
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\MarkdownConverter;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new EmojiExtension());
+$environment->mergeConfig([]);
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/inline-parsing/index.html b/1.6/customization/inline-parsing/index.html new file mode 100644 index 0000000000..b4dd9f2a9d --- /dev/null +++ b/1.6/customization/inline-parsing/index.html @@ -0,0 +1,547 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getCharacters()

+ +

This method should return an array of single characters which the inline parser engine should stop on. When it does find a match in the current line the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has stopped at a matching character; and,
  2. +
  3. No other inline parsers have successfully parsed the character
  4. +
+ +

Parameters

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the current line/character for any reason. (The Cursor state should be restored before returning false if modified). Other parsers will then have a chance to try parsing the line. If all registered parsers return false, the character will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return ['@'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+        // Save the cursor state in case we need to rewind and bail
+        $previousState = $cursor->saveState();
+        // Advance past the @ symbol to keep parsing simpler
+        $cursor->advance();
+        // Parse the handle
+        $handle = $cursor->match('/^[A-Za-z0-9_]{1,15}(?!\w)/');
+        if (empty($handle)) {
+            // Regex failed to match; this isn't a valid Twitter handle
+            $cursor->restoreState($previousState);
+            return false;
+        }
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Image;
+use League\CommonMark\Inline\Parser\InlineParserInterface;
+use League\CommonMark\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getCharacters(): array
+    {
+        return [':'];
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // The next character must be a paren; if not, then bail
+        // We use peek() to quickly check without affecting the cursor
+        $nextChar = $cursor->peek();
+        if ($nextChar !== '(' && $nextChar !== ')') {
+            return false;
+        }
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($nextChar === ')') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($nextChar === '(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/inline-rendering/index.html b/1.6/customization/inline-rendering/index.html new file mode 100644 index 0000000000..f20d9a00e4 --- /dev/null +++ b/1.6/customization/inline-rendering/index.html @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + Inline Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Inline Rendering

+ +

Inline renderers are responsible for converting the parsed inline elements into their HTML representation.

+ +

All inline renderers should implement InlineRendererInterface and its render() method:

+ +

render()

+ +

Block elements are responsible for calling $htmlRenderer->renderInlines() if they contain inline elements. This in turns causes the HtmlRenderer to call this render() method whenever a supported inline element is encountered.

+ +

If the method can only handle certain inline types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the entire inline and any contents. This can be an HtmlElement object (preferred; castable to a string) or a string of raw HTML.

+ +

You are responsible for handling any escaping that may be necessary.

+ +

Return null if your renderer cannot handle the given inline element - the next-highest priority renderer will then be given a chance to render it.

+ +

Designating Inline Renderers

+ +

When registering your render, you must tell the Environment which inline element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+// First param - the inline class type that should use our renderer
+// Second param - instance of the block renderer
+$environment->addInlineRenderer('League\CommonMark\Inline\Element\Link', new MyCustomLinkRenderer());
+
+ +

Example

+ +

Here’s a custom renderer which puts a special class on links to external sites:

+ +
use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\Environment;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+use League\CommonMark\HtmlElement;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+    private $host;
+
+    public function __construct($host)
+    {
+        $this->host = $host;
+    }
+
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . get_class($inline));
+        }
+
+        $attrs = array();
+
+        $attrs['href'] = $htmlRenderer->escape($inline->getUrl(), true);
+
+        if (isset($inline->attributes['title'])) {
+            $attrs['title'] = $htmlRenderer->escape($inline->data['title'], true);
+        }
+
+        if ($this->isExternalUrl($inline->getUrl())) {
+            $attrs['class'] = 'external-link';
+        }
+
+        return new HtmlElement('a', $attrs, $htmlRenderer->renderInlines($inline->children()));
+    }
+
+    private function isExternalUrl($url)
+    {
+        return parse_url($url, PHP_URL_HOST) !== $this->host;
+    }
+}
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addInlineRenderer(Link::class, new MyCustomLinkRenderer());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/customization/overview/index.html b/1.6/customization/overview/index.html new file mode 100644 index 0000000000..2e7ad0939d --- /dev/null +++ b/1.6/customization/overview/index.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders you need
  2. +
  3. Set custom configuration options within the Environment
  4. +
  5. Instantiate a DocParser and HtmlRenderer using that Environment
  6. +
  7. Use the DocParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  8. +
  9. Use the HtmlRenderer to convert the AST Document into HTML
  10. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->mergeConfig([
+    'html_input' => 'strip',
+]);
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renders convert the parsed blocks/inlines from the AST representation into HTML. There are two types of renderers:

+ + + +

When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you +to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/attributes/index.html b/1.6/extensions/attributes/index.html new file mode 100644 index 0000000000..0a5a47db40 --- /dev/null +++ b/1.6/extensions/attributes/index.html @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+{#id .class}
+## Header
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the extension
+$environment->addExtension(new AttributesExtension());
+
+// Set your configuration if needed
+$environment->mergeConfig([
+    // ...
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/autolinks/index.html b/1.6/extensions/autolinks/index.html new file mode 100644 index 0000000000..df1dfb4930 --- /dev/null +++ b/1.6/extensions/autolinks/index.html @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Set your configuration if needed
+$environment->mergeConfig([
+    // ...
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a separate Mention extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/commonmark/index.html b/1.6/extensions/commonmark/index.html new file mode 100644 index 0000000000..ce3dc0c9d5 --- /dev/null +++ b/1.6/extensions/commonmark/index.html @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically included for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Or if you call the Environment::createCommonMarkEnvironment() helper:

+ +
use League\CommonMark\DocParser;
+use League\CommonMark\Environment;
+use League\CommonMark\HtmlRenderer;
+
+$environment = Environment::createCommonMarkEnvironment();
+
+$parser = new DocParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderBlock($document);
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Set your configuration if needed
+$environment->mergeConfig([
+    // ...
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/disallowed-raw-html/index.html b/1.6/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..5ec2ad0bf9 --- /dev/null +++ b/1.6/extensions/disallowed-raw-html/index.html @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically filters certain HTML tags when rendering output, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Set your configuration if needed
+$environment->mergeConfig([
+    // ...
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I cannot change the page <title>anymore</title>');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/external-links/index.html b/1.6/extensions/external-links/index.html new file mode 100644 index 0000000000..a549f0aa26 --- /dev/null +++ b/1.6/extensions/external-links/index.html @@ -0,0 +1,548 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Set your configuration
+$environment->mergeConfig([
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($config, $environment);
+echo $converter->convertToHtml('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +

+use League\CommonMark\ElementRendererInterface;
+use League\CommonMark\HtmlElement;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\Inline\Element\Link;
+use League\CommonMark\Inline\Renderer\InlineRendererInterface;
+
+class MyCustomLinkRenderer implements InlineRendererInterface
+{
+
+    /**
+     * @param Link                     $inline
+     * @param ElementRendererInterface $htmlRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(AbstractInline $inline, ElementRendererInterface $htmlRenderer)
+    {
+        if (!($inline instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible inline type: ' . \get_class($inline));
+        }
+
+        if ($inline->getData('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to add a custom icon by targeting the html_class given in the configuration:

+ +
$config = [
+    'external_link' => [
+        'html_class' => 'external',
+    ],
+];
+
+ +
/**
+ * Custom SVG Icon.
+ */
+a[target="_blank"]::after,
+a.external::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link External (https://iconify.design/icon-sets/octicon/link-external.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 12 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M11 10h1v3c0 .55-.45 1-1 1H1c-.55 0-1-.45-1-1V3c0-.55.45-1 1-1h3v1H1v10h10v-3zM6 2l2.25 2.25L5 7.5 6.5 9l3.25-3.25L12 8V2H6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/footnotes/index.html b/1.6/extensions/footnotes/index.html new file mode 100644 index 0000000000..05f913ca9d --- /dev/null +++ b/1.6/extensions/footnotes/index.html @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1">&#8617;</a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Set your configuration
+$environment->mergeConfig([
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/github-flavored-markdown/index.html b/1.6/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..e926a21576 --- /dev/null +++ b/1.6/extensions/github-flavored-markdown/index.html @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+$environment->mergeConfig([]);
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = Environment::createCommonMarkEnvironment();
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+$environment->mergeConfig([]);
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/heading-permalinks/index.html b/1.6/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..bd930078ed --- /dev/null +++ b/1.6/extensions/heading-permalinks/index.html @@ -0,0 +1,624 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Normalizer\SlugNormalizer;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Set your configuration
+$environment->mergeConfig([
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'user-content',
+        'insert' => 'before',
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'slug_normalizer' => new SlugNormalizer(),
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

inner_contents (deprecated since 1.5.0)

+ +

This controls the HTML you want to appear inside of the generated <a> tag. Usually this would be something you would +style as some kind of link icon, but you can replace this with any custom HTML you wish.

+ +

This option was deprecated in 1.5.0 and will be removed in 2.0.0. Use the symbol option instead.

+ +

This option has no default value and if one is provided, a deprecation warning will be triggered and the symbol +config option below will be ignored completely.

+ +

See the Upgrade Guide for more information.

+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

slug_normalizer

+ +

“Slugs” are the strings used within the href, name, and id attributes to identify a particular permalink. +By default, this extension will generate slugs based on the contents of the heading, just like GitHub-Flavored Markdown does.

+ +

You can change the string that is used as the “slug” by setting the slug_normalizer option to any class that implements TextNormalizerInterface.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'heading_permalink' => [
+        // ... other options here ...
+        'slug_normalizer' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'heading_permalink' => [
+        // ... other options here ...
+        'slug_normalizer' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/inlines-only/index.html b/1.6/extensions/inlines-only/index.html new file mode 100644 index 0000000000..9795cd08a2 --- /dev/null +++ b/1.6/extensions/inlines-only/index.html @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Create a new, empty environment
+$environment = new Environment();
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Set any custom configuration options you wish
+$environment->mergeConfig([]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/mentions/index.html b/1.6/extensions/mentions/index.html new file mode 100644 index 0000000000..ed37b9763e --- /dev/null +++ b/1.6/extensions/mentions/index.html @@ -0,0 +1,637 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which symbol prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting symbol prefix, a regular expression pattern to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go.
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Set your configuration.
+$environment->mergeConfig([
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the last one registered will
+        // always take precedence.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://twitter.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regex pattern, or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Inline\Element\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go.
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Set your configuration.
+$environment->mergeConfig([
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Set your configuration.
+$environment->mergeConfig([
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/overview/index.html b/1.6/extensions/overview/index.html new file mode 100644 index 0000000000..77b9182e7f --- /dev/null +++ b/1.6/extensions/overview/index.html @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+$environment->mergeConfig([]);
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = Environment::createCommonMarkEnvironment();
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->mergeConfig([]);
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/smart-punctuation/index.html b/1.6/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..6f2360e067 --- /dev/null +++ b/1.6/extensions/smart-punctuation/index.html @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Set your configuration
+$environment->mergeConfig([
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/strikethrough/index.html b/1.6/extensions/strikethrough/index.html new file mode 100644 index 0000000000..0434420fd5 --- /dev/null +++ b/1.6/extensions/strikethrough/index.html @@ -0,0 +1,423 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/table-of-contents/index.html b/1.6/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..1fb81a353b --- /dev/null +++ b/1.6/extensions/table-of-contents/index.html @@ -0,0 +1,579 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\TableOfContents\TableOfContentsExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Set your configuration
+$environment->mergeConfig([
+    // Extension defaults are shown below
+    // If you're happy with the defaults, feel free to remove them from this array
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+]);
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/tables/index.html b/1.6/extensions/tables/index.html new file mode 100644 index 0000000000..2e67102aad --- /dev/null +++ b/1.6/extensions/tables/index.html @@ -0,0 +1,468 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/extensions/task-lists/index.html b/1.6/extensions/task-lists/index.html new file mode 100644 index 0000000000..9223e89778 --- /dev/null +++ b/1.6/extensions/task-lists/index.html @@ -0,0 +1,432 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Obtain a pre-configured Environment with all the CommonMark parsers/renderers ready-to-go
+$environment = Environment::createCommonMarkEnvironment();
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convertToHtml($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/index.html b/1.6/index.html new file mode 100644 index 0000000000..8ef2acdfdf --- /dev/null +++ b/1.6/index.html @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/installation/index.html b/1.6/installation/index.html new file mode 100644 index 0000000000..866ce2a9ab --- /dev/null +++ b/1.6/installation/index.html @@ -0,0 +1,404 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +

In your project root just run:

+ +
composer require league/commonmark:^1.6
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^1.6. This is equivalent to >=1.6 <2.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/security/index.html b/1.6/security/index.html new file mode 100644 index 0000000000..7d9dec6dc1 --- /dev/null +++ b/1.6/security/index.html @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/support/index.html b/1.6/support/index.html new file mode 100644 index 0000000000..6b6c665f76 --- /dev/null +++ b/1.6/support/index.html @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/1.6/upgrading/index.html b/1.6/upgrading/index.html new file mode 100644 index 0000000000..d613dfd57c --- /dev/null +++ b/1.6/upgrading/index.html @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.5 - 1.6 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 1.6. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 1.5 to 1.6

+ +

Configuration changes

+ +

The upcoming v2.0 release is going to change the keys/paths for several configuration options. To help prepare for that change, we’ve added support for the new keys/paths:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Current Key/PathNew Key/PathNotes
enable_emcommonmark/enable_em 
enable_strongcommonmark/enable_strong 
use_asteriskcommonmark/use_asterisk 
use_underscorecommonmark/use_underscore 
unordered_list_markerscommonmark/unordered_list_markers 
mentions/*/symbolmentions/*/prefix 
mentions/*/regexmentions/*/patternShould not contain starting/ending / delimiters or flags - must be a partial regex
+ +

Additionally, 2.0 will not support using floats for the max_nesting_level option.

+ +

Version 1.6 will support both the 1.x and 2.0 variations mentioned above but 2.0 won’t, so consider changing them now:

+ +
 $config = [
+     'html_input' => 'escape',
+     'allow_unsafe_links' => false,
+-    'max_nesting_level' => INF,
++    'max_nesting_level' => PHP_INT_MAX,
+     'renderer' => [
+         'block_separator' => "\n",
+         'inner_separator' => "\n",
+         'soft_break'      => "\n",
+     ],
+-    'enable_em' => true,
+-    'enable_strong' => true,
+-    'use_asterisk' => true,
+-    'use_underscore' => true,
+-    'unordered_list_markers' => ['-', '+', '*'],
++    'commonmark' => [
++        'enable_em' => true,
++        'enable_strong' => true,
++        'use_asterisk' => true,
++        'use_underscore' => true,
++        'unordered_list_markers' => ['-', '+', '*'],
++    ],
+     'mentions' => [
+         'github_handle' => [
+-            'symbol'    => '@',
+-            'regex'     => '/[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)/i',
++            'prefix'    => '@',
++            'regex'     => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+             'generator' => 'https://github.com/%s',
+         ],
+     ],
+ ];
+
+ +

Converters with custom environments

+ +

Version 2.0 will no longer allow custom environments to be injected via the constructors of CommonMarkConverter or GithubFlavoredMarkdownConverter. You should instead use the newly-added MarkdownConverter class:

+ +
-use League\CommonMark\CommonMarkConverter;
+ use League\CommonMark\Environment;
+ use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
++use League\CommonMark\MarkdownConverter;
+
+ $config = [
+     'html_input' => 'escape',
+     'allow_unsafe_links' => false,
+ ];
+
+ $environment = Environment::createCommonMarkEnvironment();
+ $environment->addExtension(new InlinesOnlyExtension());
++$environment->mergeConfig($config);
+
+ // Go forth and convert you some Markdown!
+-$converter = new CommonMarkConverter($config, $environment);
++$converter = new MarkdownConverter($environment);
+ echo $converter->convertToHtml('# Hello World!');
+
+ +

Environment and Configuration method changes

+ +

The environment’s setConfig() method is now deprecated and will be removed in 2.0 - use mergeConfig() instead.

+ +

Calling ConfigurableEnvironmentInterface::mergeConfig() without the array parameter is deprecated and won’t be allowed in 2.0.

+ +

Calling Configuration::getConfig() without any parameters to retrieve the full configuration is deprecated and won’t be allowed in 2.0. Future versions should only fetch the config items they need, not the whole configuration.

+ +

Calling Configuration::set() without the second $value parameter is deprecated and won’t be allowed in 2.0. You should always explicitly define the value you want to be set.

+ +

RegexHelper::matchAll()

+ +

The RegexHelper::matchAll() method has been deprecated and will be removed in 2.0. Use the new, more-efficient RegexHelper::matchFirst() method instead.

+ +

Extending ArrayCollection

+ +

The ArrayCollection class will be marked final in 2.0 so avoid extending it.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/basic-usage/index.html b/2.0/basic-usage/index.html new file mode 100644 index 0000000000..10a563acee --- /dev/null +++ b/2.0/basic-usage/index.html @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Using Extensions

+ +

The CommonMarkConverter and GithubFlavoredMarkdownConverter shown above automatically configure the environment for you, but if you want to use additional extensions you’ll need to avoid those classes and use the generic MarkdownConverter class instead to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

Configuration

+ +

If you’re using the CommonMarkConverter or GithubFlavoredMarkdownConverter class you can pass configuration options directly into their constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

See the configuration section for more information on the available configuration options.

+ +

Supported Character Encodings

+ +

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.

+ +

Return Value

+ +

The convertToHtml() method actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final HTML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/changelog/index.html b/2.0/changelog/index.html new file mode 100644 index 0000000000..2f2845ab31 --- /dev/null +++ b/2.0/changelog/index.html @@ -0,0 +1,1299 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 2.x releases are shown below. See the full list of releases for the complete changelog.

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

2.4.4 - 2024-07-22

+ +

Fixed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

+ +

2.4.3 - 2024-07-22

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.2…2.4.3

+ +

2.4.2 - 2024-02-02

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.1…2.4.2

+ +

2.4.1 - 2023-08-30

+ +

Fixed

+ + + +

2.4.0 - 2023-03-24

+ +

See the upgrading guide for more information about the exception-related changes

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

2.3.9 - 2023-02-15

+ +

Fixed

+ + + +

2.3.8 - 2022-12-10

+ +

Fixed

+ + + +

2.3.7 - 2022-11-17

+ +

Fixed

+ + + +

2.3.6 - 2022-10-30

+ +

Fixed

+ + + +

2.3.5 - 2022-07-29

+ +

Fixed

+ + + +

2.3.4 - 2022-07-17

+ +

Changed

+ + + +

Fixed

+ + + +

2.3.3 - 2022-06-07

+ +

Fixed

+ + + +

2.3.2 - 2022-06-03

+ +

Fixed

+ + + +

2.2.5 - 2022-06-03

+ +

Fixed

+ + + +

2.3.1 - 2022-05-14

+ +

Fixed

+ + + +

2.2.4 - 2022-05-14

+ +

Fixed

+ + + +

2.3.0 - 2022-04-07

+ +

Added

+ + + +

Deprecated

+ + + +

2.2.3 - 2022-02-26

+ +

Fixed

+ + + +

2.1.3 - 2022-02-26

+ +

Fixed

+ + + +

2.0.4 - 2022-02-26

+ +

Fixed

+ + + +

2.2.2 - 2022-02-13

+ +

Fixed

+ + + +

2.1.2 - 2022-02-13

+ +

Fixed

+ + + +

2.0.3 - 2022-02-13

+ +

Fixed

+ + + +

2.2.1 - 2022-01-25

+ +

Fixed

+ + + +

Removed

+ + + +

2.2.0 - 2022-01-22

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

2.1.1 - 2022-01-02

+ +

Added

+ + + +

2.1.0 - 2021-12-05

+ +

Added

+ + + +

Fixed

+ + + +

2.0.2 - 2021-08-14

+ +

Changed

+ + + +

Fixed

+ + + +

2.0.1 - 2021-07-31

+ +

Fixed

+ + + +

2.0.0 - 2021-07-24

+ +

No changes were introduced since the previous 2.0.0-rc2 release.

+ +

Please refer to the full Changelog for a list of all changes between 1.x and 2.0. An upgrading guide is also available.

+ +

2.0.0-rc2 - 2021-07-17

+ +

Fixed

+ + + +

2.0.0-rc1 - 2021-07-10

+ +

No changes were introduced since the previous release.

+ +

2.0.0-beta3 - 2021-07-03

+ +

Changed

+ + + +

2.0.0-beta2 - 2021-06-27

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

2.0.0-beta1 - 2021-06-20

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Removed

+ + + +

Deprecated

+ +

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

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/configuration/index.html b/2.0/configuration/index.html new file mode 100644 index 0000000000..19973f7801 --- /dev/null +++ b/2.0/configuration/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the Environment or converter classes when creating them:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+    'slug_normalizer' => [
+        'max_length' => 255,
+    ],
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of the core configuration options available:

+ + + +

Additional configuration options are available for most of the available extensions - refer to their individual documentation for more details. For example, the CommonMark core extension offers these additional options:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/abstract-syntax-tree/index.html b/2.0/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..cca90877e2 --- /dev/null +++ b/2.0/customization/abstract-syntax-tree/index.html @@ -0,0 +1,702 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Visualization

+ +

Even with an interactive debugger it can be tricky to view an entire tree at once. Consider using the XmlRenderer to provide a simple text-based representation of the AST for debugging purposes.

+ +

Node Traversal

+ +

There are four different ways to traverse/iterate the Nodes within the AST:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodProsCons
Manual TraversalBest way to access/check direct relatives of nodesNot useful for iteration
Iterating the TreeFast and efficientPossible unexpected behavior when adding/removing sibling nodes while iterating
Walking the TreeFull control over iterationUp to twice as slow as iteration; adding/removing nodes while iterating can lead to weird behaviors
Querying NodesEasier to write and understand; no weird behaviorsNot memory efficient
+ +

Each is described in more detail below

+ +

Manual Traversal

+ +

The following methods can be used to manually traverse from one Node to any of its direct relatives:

+ + + +

This is best suited for situations when you need to know information about those relatives.

+ +

Iterating the Tree

+ +

If you’d like to iterate through all the nodes, use the iterator() method to obtain an iterator that will loop through each node in the tree (using pre-order traversal):

+ +
foreach ($document->iterator() as $node) {
+    echo 'Current node: ' . get_class($node) . "\n";
+}
+
+ +

Given an AST like this (XML representation):

+ +
<document>
+  <heading level="1">
+    <text>Hello World!</text>
+  </heading>
+  <paragraph>
+    <text>This is an example of </text>
+    <strong>
+      <text>CommonMark</text>
+    </strong>
+    <text>.</text>
+  </paragraph>
+</document>
+
+ +

The code above will output:

+ +
Current node: League\CommonMark\Node\Block\Document
+Current node: League\CommonMark\Extension\CommonMark\Node\Block\Heading
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Block\Paragraph
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Extension\CommonMark\Node\Inline\Strong
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Inline\Text
+
+ +

This iterator doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes. It’s also very CPU and memory-efficient.

+ +

Be careful when modifying nodes while iterating the tree as some of those changes may affect the current iteration process, especially for sibling nodes that come after the current one. For example, if you remove the current node’s next() sibling, the next loop of that iteration will still include the removed sibling even though it was successfully removed from the AST. Similarly, any new siblings that are added won’t be visited on the next loop.

+ +

Walking the Tree

+ +

If you’d like to walk through all the nodes, visiting each one as you enter and leave it, use the walker() method to obtain an instance of NodeWalker. This also uses pre-order traversal but emitting NodeWalkerEvents along the way:

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'Now ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

Using the same example AST in the previous section, this code will output:

+ +
Now entering a League\CommonMark\Node\Block\Document node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Block\Paragraph node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Node\Block\Paragraph node
+Now leaving a League\CommonMark\Node\Block\Document node
+
+ +

This approach offers many of the same benefits as the simple iteration shown in the previous section such as memory efficiency and no recursion. The key differences come from how you enter and leave nodes:

+ +
    +
  1. Iteration can potentially take twice as long - not ideal for performance
  2. +
  3. Provides you with more control over exactly when an action is taken on a node which is sometimes needed for certain AST manipulations
  4. +
  5. Also provides a resumeAt() method to override where it should iterate next
  6. +
+ +

But like with the iterator, be careful when adding/removing nodes while walking the tree, as there are even more subtle cases where the walker could even lose track of where it was, which may result in some nodes being visited multiple times or not at all.

+ +

Querying Nodes

+ +

If you’re trying to locate certain nodes to perform actions on them, querying the nodes from the AST might be easier to implement. This can be done with the Query class:

+ +
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Query;
+
+// Find all paragraphs and blockquotes that contain links
+$matchingNodes = (new Query())
+    ->where(Query::type(Paragraph::class))
+    ->orWhere(Query::type(BlockQuote::class))
+    ->andWhere(Query::hasChild(Query::type(Link::class)))
+    ->findAll($document);
+
+foreach ($matchingNodes as $node) {
+    // TODO: Do something with them
+}
+
+ +

Each condition passed into where(), orWhere(), or andWhere() must be a callable “filter” that accepts a Node and returns true or false. We provide several methods that can help create these filters for you:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Query::type(string $class)Creates a filter that matches nodes with the given class name
Query::hasChild()Creates a filter that matches nodes which contain at least one child
Query::hasChild(callable $condition)Creates a filter that matches nodes which contain at least one child that matches the inner $condition
Query::hasParent()Creates a filter that matches nodes which have a parent
Query::hasParent(callable $condition)Creates a filter that matches nodes which have a parent that matches the inner $condition
+ +

You can of course create your own custom filters/conditions using an anonymous function or by implementing ExpressionInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Node\Query;
+use League\CommonMark\Node\Query\ExpressionInterface;
+
+class ChildCountGreaterThan implements ExpressionInterface
+{
+    private $count;
+
+    public function __construct(int $count)
+    {
+        $this->count = $count;
+    }
+
+    public function __invoke(Node $node) : bool{
+        return count($node->children()) > $this->count;
+    }
+}
+
+$query = (new Query())
+    ->where(function (Node $node): bool { return $node->data->has('attributes/class'); })
+    ->andWhere(new ChildCountGreaterThan(3));
+
+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ +

Data Storage

+ +

Each Node has a property called data which is a Data (array-like) object. This can be used to store any arbitrary data you’d like on the node:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text1 = new Text('Hello, world!');
+$text1->data->set('language', 'English');
+$text1->data->set('is_good_translation', true);
+
+$text2 = new Text('Bonjour monde!');
+$text2->data->set('language', 'French');
+$text2->data->set('is_good_translation', false);
+
+foreach ([$text1, $text2] as $text) {
+    if ($text->data->get('is_good_translation')) {
+        sprintf('In %s we would say: "%s"', $text->data->get('language'), $text->getLiteral());
+    } else {
+        sprintf('I think they would say "%s" in %s, but I\'m not sure.', $text->getLiteral(), $text->data->get('language'));
+    }
+}
+
+ +

You can also access deeply-nested paths using / or . as delimiters:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text = new Text('Hello, world!');
+$text->data->set('info', ['language' => 'English', 'is_good_translation' => true]);
+
+var_dump($text->data->get('info/language'));
+var_dump($text->data->get('info.is_good_translation'));
+
+$text->data->set('info/is_example', true);
+
+ +

HTML Attributes

+ +

The data property comes pre-instantiated with a single data element called attributes which is used to store any HTML attributes that need to be rendered. For example:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+$link = new Link('https://twitter.com/colinodell', '@colinodell');
+$link->data->append('attributes/class', 'social-link');
+$link->data->append('attributes/class', 'twitter');
+$link->data->set('attributes/target', '_blank');
+$link->data->set('attributes/rel', 'noopener');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/block-parsing/index.html b/2.0/customization/block-parsing/index.html new file mode 100644 index 0000000000..f22dd9ef0c --- /dev/null +++ b/2.0/customization/block-parsing/index.html @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

At a high level, block parsing is a two-step process:

+ +
    +
  1. Using a BlockStartParserInterface to identify if/where a block start exists on the given line
  2. +
  3. Using a BlockContinueParserInterface to perform additional processing of the identified block
  4. +
+ +

So to implement a custom block parser you will actually need to implement both of these classes.

+ +

BlockStartParserInterface

+ +

Instances of this interface have a single tryStart() method:

+ +
/**
+ * Check whether we should handle the block at the current position
+ *
+ * @param Cursor                       $cursor
+ * @param MarkdownParserStateInterface $parserState
+ *
+ * @return BlockStart|null
+ */
+public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart;
+
+ +

Given a Cursor at the current position, plus some extra information about the state of the parser, this method is responsible for determining whether a particular type of block seems to exist at the given position. You don’t actually parse the block here - that’s the job of a BlockContinueParserInterface. Your only job here is to return whether or not a particular type of block does exist here, and if so which block parser should parse it.

+ +

If you find that you cannot parse the given block, you should return BlockStart::none(); from this function.

+ +

However, if the Markdown at the current position does indeed seem to be the type of block you’re looking for, you should return a BlockStart instance using the following static constructor pattern:

+ +
use League\CommonMark\Parser\Block\BlockStart;
+
+return BlockStart::of(new MyCustomParser())->at($cursor);
+
+ +

Unlike in 1.x, the Cursor state is no longer shared between parsers. You must therefore explicitly provide the BlockStart object with a copy of your cursor at the correct, post-parsing position.

+ +

NOTE: If your custom block starts with a letter character you’ll need to add your parser to the environment with a priority of 250 or higher. This is due to a performance optimization where such lines are usually skipped.

+ +

BlockContinueParserInterface

+ +

The previous interface only helps the engine identify where a block starts. Additional information about the block, as well as the ability to parse additional lines of input, is all handled by the BlockContinueParserInterface.

+ +

This interface has several methods, so it’s usually easier to extend from AbstractBlockContinueParser instead, which sets most of the methods to use typical defaults you can override as needed.

+ +

getBlock()

+ +
public function getBlock(): AbstractBlock;
+
+ +

Each instance of a BlockContinueParserInterface is associated with a new block that is being parsed. This method here returns that block.

+ +

isContainer()

+ +
public function isContainer(): bool;
+
+ +

This method returns whether or not the block is a “container” capable of containing other blocks as children.

+ +

canContain()

+ +
public function canContain(AbstractBlock $childBlock): bool;
+
+ +

This method returns whether the current block being parsed can contain the given child block.

+ +

canHaveLazyContinuationLines()

+ +
public function canHaveLazyContinuationLines(): bool;
+
+ +

This method returns whether or not this parser should also receive subsequent lines of Markdown input. This is primarily used when a block can span multiple lines, like code blocks do.

+ +

addLine()

+ +
public function addLine(string $line): void;
+
+ +

If canHaveLazyContinuationLines() returned true, this method will be called with the additional lines of content.

+ +

tryContinue()

+ +
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue;
+
+ +

This method allows you to try and parse an additional line of Markdown.

+ +

closeBlock()

+ +
public function closeBlock(): void;
+
+ +

This method is called when the block is done being parsed. Any final adjustments to the block should be made at this time.

+ +

parseInlines()

+ +
public function parseInlines(InlineParserEngineInterface $inlineParser): void;
+
+ +

This method is called when the engine is ready to parse any inline child elements.

+ +

Note: For performance reasons, this method is not part of BlockContinueParserInterface. If your block may contain inlines, you should make sure that your “continue parser” also implements BlockContinueParserWithInlinesInterface.

+ +

Tips

+ +

Here are some additional tips to consider when writing your own custom parsers:

+ +

Combining both into one file

+ +

Although parsing requires two classes, you can use the anonymous class feature of PHP to combine both into a single file! Here’s an example:

+ +
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+
+final class MyCustomBlockParser extends AbstractBlockContinueParser
+{
+    // TODO: implement your continuation parsing methods here
+
+    public static function createBlockStartParser(): BlockStartParserInterface
+    {
+        return new class implements BlockStartParserInterface
+        {
+            // TODO: implement the tryStart() method here
+        };
+    }
+}
+
+
+ +

Performance

+ +

The BlockStartParserInterface::tryStart() and BlockContinueParserInterface::tryContinue() methods may be called hundreds or thousands of times during execution. For best performance, have your methods return as early as possible, and make sure your code is highly optimized.

+ +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

If your block contains literal strings/text within the block (and not as part of a child block), you should have your custom block type also implement StringContainerInterface.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/configuration/index.html b/2.0/customization/configuration/index.html new file mode 100644 index 0000000000..a7f76db83f --- /dev/null +++ b/2.0/customization/configuration/index.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Configuration Schemas and Values

+ +

Version 2.0 introduced a new robust system for defining configuration schemas and accessing them within custom extensions.

+ +

Configuration Schemas

+ +

Unlike in 1.x, all configuration options must have a defined schema. This defines which options are available, what types of values they accept, whether any are required, and any default values you wish to define if the user doesn’t provide any.

+ +

These custom options can be defined from within your custom extension by implementing the ConfigurableExtensionInterface:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+use Nette\Schema\Expect;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        $builder->addSchema('my_extension', Expect::structure([
+            'enable_some_feature' => Expect::bool()->default(true),
+            'html_class' => Expect::string()->default('my-custom-extension'),
+            'align' => Expect::anyOf('left', 'center', 'right')->default('left'),
+            'favorite_number' => Expect::int()->min(1)->max(100)->default(42),
+        ]));
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        // TODO: Implement register() method
+    }
+}
+
+ +

See the league/config documentation for more examples of how to define custom configuration schemas.

+ +

Note that you only need to implement ConfigurableExtensionInterface if you plan to define new configuration options - you don’t need this if you’re only reading existing options.

+ +

Reading Configuration Values

+ +

Okay, so your extension has defined the different options that are available, but now you want to start using them within your custom extension. There are a few ways you can access the values:

+ +

During Extension Registration

+ +

Perhaps your extension needs to decide whether/how to register certain parsers/renderers/etc based on the user-provided configuration values - in that case, you can read the value from the $environment - for example:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        // (see code example above)
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        if ($environment->getConfiguration()->get('my_extension/enable_some_feature')) {
+            $environment->addBlockStartParser(new MyCustomParser());
+            $environment->addRenderer(MyCustomBlockType::class, new MyCustomRenderer());
+        }
+    }
+}
+
+ +

Within Parsers/Renderers/Listeners

+ +

Perhaps you want to reference those configuration values from within a custom parser, renderer, event listener, or something else. This can easily by done by having that class also implement ConfigurationAwareInterface. This interface signals to the Environment that your class needs a copy of the final configuration so it can read it later:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+
+final class MyCustomRenderer implements NodeRendererInterface, ConfigurationAwareInterface
+{
+    /**
+     * @var ConfigurationInterface
+     */
+    private $config;
+
+    public function setConfiguration(ConfigurationInterface $configuration): void
+    {
+        $this->config = $configuration;
+    }
+
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return 'My favorite number is ' . $this->config->get('my_extension/favorite_number');
+    }
+}
+
+ +

You can access any configuration value from here, not just the ones you might have defined yourself.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/cursor/index.html b/2.0/customization/cursor/index.html new file mode 100644 index 0000000000..a4e1ea0a21 --- /dev/null +++ b/2.0/customization/cursor/index.html @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Parser\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter(int $index)Returns the character at the given absolute position
getCurrentCharacter()Returns the character at the current position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/delimiter-processing/index.html b/2.0/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..611f280972 --- /dev/null +++ b/2.0/customization/delimiter-processing/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis;
+
+// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
use League\CommonMark\Delimiter\Delimiter;
+use League\CommonMark\Node\Inline\Text;
+
+$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/environment/index.html b/2.0/customization/environment/index.html new file mode 100644 index 0000000000..5b5b194594 --- /dev/null +++ b/2.0/customization/environment/index.html @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all extensions, parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

An empty Environment can be obtained like this:

+ +
use League\CommonMark\Environment\Environment;
+
+$config = [];
+$environment = new Environment($config);
+
+ +

You can customize the Environment using any of the methods below (from the EnvironmentBuilderInterface interface).

+ +

Once your Environment is configured with whatever configuration and extensions you want, you can instantiate a MarkdownConverter and start converting MD to HTML:

+ +
use League\CommonMark\MarkdownConverter;
+
+// Using $environment from the previous code sample
+$converter = new MarkdownConverter($environment);
+
+echo $converter->convertToHtml('# Hello World!');
+
+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. For example, if you want core CommonMark functionality plus footnote support:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+$config = [];
+$environment = new Environment($config);
+
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new FootnoteExtension());
+
+ +

addBlockStartParser()

+ +
public function addBlockStartParser(BlockStartParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockStartParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addRenderer()

+ +
public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0);
+
+ +

Registers a NodeRendererInterface to handle a specific type of AST node ($nodeClass) with the given priority (a higher number will be executed earlier).

+ +

See Rendering for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/event-dispatcher/index.html b/2.0/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..3d49112827 --- /dev/null +++ b/2.0/customization/event-dispatcher/index.html @@ -0,0 +1,574 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic, PSR-14-compliant event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code.

+ +

Event Class

+ +

Any PSR-14 compliant event can be used, though we also provide an AbstractEvent class you can use to easily create your own events:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - the event object to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

League\CommonMark\Event\DocumentPreRenderEvent

+ +

This event is dispatched by the renderer just before rendering begins. Like with DocumentParsedEvent, this offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering, but with the added knowledge of which format is being rendered to (e.g. html).

+ +

League\CommonMark\Event\DocumentRenderedEvent

+ +

This event is dispatched once the rendering step has been completed, just before the output is returned. The final output can be adjusted at this point or additional metadata can be attached to the return object.

+ +

Bring Your Own PSR-14 Event Dispatcher

+ +

Although this library provides PSR-14 compliant event dispatching out-of-the-box, you may want to use your own PSR-14 event dispatcher instead. This is possible as long as that third-party library both:

+ +
    +
  1. Implements the PSR-14 EventDispatcherInterface; and,
  2. +
  3. Allows you to register additional ListenerProviderInterface instances with that dispatcher library
  4. +
+ +

Not all libraries support this so please check carefully! Assuming yours does, delegating all the event behavior to that library can be done with two steps:

+ +

First, call the setEventDispatcher() method on the Environment to register that other implementation. With that done, any calls to Environment::dispatch() will be passed through to that other dispatcher. But we still need to let that dispatcher know about the events registered by CommonMark extensions, otherwise nothing will happen when events are dispatched.

+ +

Because the Environment implements PSR-14’s ListenerProviderInterface you’ll also need to pass the configured Environment object to your event dispatcher so that it becomes aware of those available events.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event): void
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data->append('attributes/class', 'external-link');
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfiguration()->get('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = new Environment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/extensions/index.html b/2.0/customization/extensions/index.html new file mode 100644 index 0000000000..4279292fff --- /dev/null +++ b/2.0/customization/extensions/index.html @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a EnvironmentBuilderInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new EmojiExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/inline-parsing/index.html b/2.0/customization/inline-parsing/index.html new file mode 100644 index 0000000000..b8e47dde4a --- /dev/null +++ b/2.0/customization/inline-parsing/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getMatchDefinition()

+ +

This method should return an instance of InlineParserMatch which defines the text the parser is looking for. Examples of this might be something like:

+ +
use League\CommonMark\Parser\Inline\InlineParserMatch;
+
+InlineParserMatch::string('@');                  // Match any '@' characters found in the text
+InlineParserMatch::string('foo');                // Match the text 'foo' (case insensitive)
+
+InlineParserMatch::oneOf('@', '!');              // Match either character
+InlineParserMatch::oneOf('http://', 'https://'); // Match either string
+
+InlineParserMatch::regex('\d+');                 // Match the regular expression (omit the regex delimiters and any flags)
+
+ +

Once a match is found, the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has found at a matching string in the current line; and,
  2. +
  3. No other inline parsers with a higher priority have successfully parsed the text at this point in the line
  4. +
+ +

Parameters

+ + + +
InlineParserContext
+ +

This class has several useful methods:

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the text at the current position for any reason. Other parsers will then have a chance to try parsing that text. If all registered parsers return false, the text will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed/matched text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::regex('@([A-Za-z0-9_]{1,15}(?!\w))');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+
+        // This seems to be a valid match
+        // Advance the cursor to the end of the match
+        $cursor->advanceBy($inlineContext->getFullMatchLength());
+
+        // Grab the Twitter handle
+        [$handle] = $inlineContext->getSubMatches();
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+// And here's how to hook it up:
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::oneOf(':)', ':(');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($inlineContext->getFullMatch() === ':)') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($inlineContext->getFullMatch() === ':(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/overview/index.html b/2.0/customization/overview/index.html new file mode 100644 index 0000000000..115c3b166f --- /dev/null +++ b/2.0/customization/overview/index.html @@ -0,0 +1,479 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders/configuration you need
  2. +
  3. Instantiate a MarkdownParser and HtmlRenderer using that Environment
  4. +
  5. Use the MarkdownParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  6. +
  7. Use the HtmlRenderer to convert the AST Document into HTML
  8. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+$environment = new Environment([
+    'html_input' => 'strip',
+]);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderDocument($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renderers convert the parsed blocks/inlines from the AST representation into HTML. When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/rendering/index.html b/2.0/customization/rendering/index.html new file mode 100644 index 0000000000..8f2bf400e0 --- /dev/null +++ b/2.0/customization/rendering/index.html @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Custom Rendering

+ +

Renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement NodeRendererInterface and its render() method. Note that in v2.0, both +block renderers and inline renderers share the same interface and method:

+ +

render()

+ +
public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The HtmlRenderer will call this method during the rendering process whenever a supported element is encountered.

+ +

If your renderer can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the node and its contents, including any children. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\Util\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Renderers

+ +

When registering your renderer, you must tell the Environment which node element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// First param - the node class type that should use our renderer
+// Second param - instance of the renderer
+$environment->addRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple types:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak;
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements NodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(ThematicBreak::class, new TextDividerRenderer());
+
+ +

Note that thematic breaks should not contain children, which is why the $childRenderer is unused in this example. Otherwise we’d have to call code like this and return the result as part of the rendered HTML we’re generating here: $innerHtml = $childRenderer->renderNodes($node->children());

+ +

Tips

+ + + +

XML Rendering

+ +

The XML renderer will automatically attempt to convert any AST nodes to XML by inspecting the name of the block/inline node and its attributes. You can instead control the XML element name and attributes by making your renderer implement XmlNodeRendererInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+
+class TextDividerRenderer implements NodeRendererInterface, XmlNodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+
+    public function getXmlTagName(Node $node): string
+    {
+        return 'text_divider';
+    }
+
+    public function getXmlAttributes(Node $node): array
+    {
+        return ['character' => '='];
+    }
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/customization/slug-normalizer/index.html b/2.0/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..61cb7561d9 --- /dev/null +++ b/2.0/customization/slug-normalizer/index.html @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + Slug Normalizer - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Slug Normalizer

+ +

“Slugs” are strings used within href, name, and id HTML attributes to identify particular elements within a document.

+ +

Some extensions (like the HeadingPermalinkExtension) need the ability to convert user-provided text into these URL-safe slugs while also ensuring that these are unique throughout the generated HTML. The Environment provides a pre-built normalizer you can use for this purpose.

+ +

Usage

+ +

You can obtain a reference to the built-in slug normalizer by calling $environment->getSlugNormalizer();

+ +

To use this within your extension, have your parser/renderer/whatever implement EnvironmentAwareInterface and then implement the corresponding setEnvironment method like this:

+ +

+use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Environment\EnvironmentAwareInterface;
+
+class MyCustomParserOrRenderer implements EnvironmentAwareInterface
+{
+    private $slugNormalizer;
+
+    public function setEnvironment(EnvironmentInterface $environment): void
+    {
+        $this->slugNormalizer = $environment->getSlugNormalizer();
+    }
+}
+
+ +

You can then call $this->slugNormalizer->normalize($text) as needed.

+ +

Configuration

+ +

The slug_normalizer configuration section allows you to adjust the following options:

+ +

instance

+ +

You can change the string that is used as the “slug” by setting the instance option to any class that implements TextNormalizerInterface. +We provide a simple SlugNormalizer by default, but you may want to plug in a different library or create your own normalizer instead.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

max_length

+ +

This can be configured to limit the length of that slug to prevent overly-long values. By default, that limit is 255 characters. You may set this to any positive integer, or 0 for no limit.

+ +

(Note that generated slugs might be slightly longer than this “limit” if the unique option is enabled and the slug generator detects a duplicate slug and needs to add a suffix to make it unique.)

+ +

unique

+ +

This options controls whether slugs should be unique. Possible values include:

+ + + +

You might have a use case where you’re converting several different Markdown documents on the same page and so you’d like to ensure that none of those documents use conflicting slugs. In that case, you should set the scope option to 'environment' to ensure that a single instance of a MarkdownConverter (which uses a single Environment) will never produce the same slug twice during its lifetime (which usually lasts the entire duration of a single HTTP request).

+ +

If you need complete control over how unique slugs are generated, make your 'instance' implement UniqueSlugNormalizerInterface; otherwise, we’ll simply append incremental numbers to slugs to ensure they are unique.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/attributes/index.html b/2.0/extensions/attributes/index.html new file mode 100644 index 0000000000..cefe2f1d67 --- /dev/null +++ b/2.0/extensions/attributes/index.html @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+ +

This results in the following output:

+ +
<blockquote title="Blockquote title">
+<p>A nice blockquote</p>
+</blockquote>
+
+ +

CSS-selector-style declarations can be used to set the id and class attributes:

+ +
{#id .class}
+## Header
+
+ +

Output:

+ +
<h2 class="class" id="id">Header</h2>
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Output:

+ +
<p>This is <em style="color: red">red</em>.</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/autolinks/index.html b/2.0/extensions/autolinks/index.html new file mode 100644 index 0000000000..7a4d7ce8af --- /dev/null +++ b/2.0/extensions/autolinks/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a Mention Parser outside of this extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/commonmark/index.html b/2.0/extensions/commonmark/index.html new file mode 100644 index 0000000000..bf8bda0b61 --- /dev/null +++ b/2.0/extensions/commonmark/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically installed for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new Environment with the core extension
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/default-attributes/index.html b/2.0/extensions/default-attributes/index.html new file mode 100644 index 0000000000..1457cba9fa --- /dev/null +++ b/2.0/extensions/default-attributes/index.html @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + Default Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Default Attributes

+ +

The DefaultAttributesExtension allows you to apply default HTML classes and other attributes using configuration options.

+ +

It works by applying the attributes to the nodes during the DocumentParsedEvent event - right after the nodes are parsed but before they are rendered. +(As a result, it’s possible that renderers may add other attributes - the goal of this extension is only to provide custom defaults.)

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DefaultAttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Node\Block\Paragraph;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'default_attributes' => [
+        Heading::class => [
+            'class' => static function (Heading $node) {
+                if ($node->getLevel() === 1) {
+                    return 'title-main';
+                } else {
+                    return null;
+                }
+            },
+        ],
+        Table::class => [
+            'class' => 'table',
+        ],
+        Paragraph::class => [
+            'class' => ['text-center', 'font-comic-sans'],
+        ],
+        Link::class => [
+            'class' => 'btn btn-link',
+            'target' => '_blank',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new DefaultAttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a default_attributes array. Each key in the array should be a FQCN for the node class you wish to apply the default attribute to, and the values should be a map of attribute names to attribute values.

+ +

Attribute values may be any of the following types:

+ + + +

Examples

+ +

Here’s an example that will apply Bootstrap 4 classes and attributes:

+ +
$config = [
+    'default_attributes' => [
+        Table::class => [
+            'class' => ['table', 'table-responsive'],
+        ],
+        BlockQuote::class => [
+            'class' => 'blockquote',
+        ],
+    ],
+];
+
+ +

Here’s a more complex example that uses a callable to add a class only if the paragraph immediately follows an <h1> heading:

+ +
$config = [
+    'default_attributes' => [
+        Paragraph::class => [
+            'class' => static function (Paragraph $paragraph) {
+                if ($paragraph->previous() instanceof Heading && $paragraph->previous()->getLevel() === 1) {
+                    return 'lead';
+                }
+
+                return null;
+            },
+        ],
+    ],
+];
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/description-lists/index.html b/2.0/extensions/description-lists/index.html new file mode 100644 index 0000000000..40c72ae61a --- /dev/null +++ b/2.0/extensions/description-lists/index.html @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + + Description List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Description List Extension

+ +

The DescriptionListExtension adds Markdown Extra-style description lists to facilitate the creation of <dl>, <dt>, and <dd> HTML using Markdown.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DescriptionListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\DescriptionList\DescriptionListExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DescriptionListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Some markdown goes here');
+
+ +

Syntax

+ +

The syntax is based directly on the rules and logic implemented by the Markdown Extra library. Here are some examples of sample Markdown input and HTML output demonstrating the syntax:

+ +
Apple
+:   Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.
+:   An American computer company.
+
+Orange
+:   The fruit of an evergreen tree of the genus Citrus.
+
+ +
<dl>
+    <dt>Apple</dt>
+    <dd>Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.</dd>
+    <dd>An American computer company.</dd>
+
+    <dt>Orange</dt>
+    <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+
+ +

See the Markdown Extra documentation or our own spec for additional examples.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/disallowed-raw-html/index.html b/2.0/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..ada37bbaf7 --- /dev/null +++ b/2.0/extensions/disallowed-raw-html/index.html @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically escapes certain HTML tags when rendering raw HTML, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Customize the extension's configuration if needed
+// Default values are shown below - you can omit this configuration if you're happy with those defaults
+// and don't want to customize them
+$config = [
+    'disallowed_raw_html' => [
+        'disallowed_tags' => ['title', 'textarea', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'script', 'plaintext'],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I cannot change the page <title>anymore</title>');
+
+ +

Configuration

+ +

This extension can be configured by providing a disallowed_raw_html array with the following nested configuration options. The defaults are shown in the code example above.

+ +

disallowed_tags

+ +

An array containing a list of tags that should be escaped.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/external-links/index.html b/2.0/extensions/external-links/index.html new file mode 100644 index 0000000000..dfdc14c8f3 --- /dev/null +++ b/2.0/extensions/external-links/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class MyCustomLinkRenderer implements NodeRendererInterface
+{
+    /**
+     * @param Node                       $node
+     * @param ChildNodeRendererInterface $childRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        if (!($node instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible node type: ' . \get_class($node));
+        }
+
+        if ($node->data->get('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/footnotes/index.html b/2.0/extensions/footnotes/index.html new file mode 100644 index 0000000000..d4838ba298 --- /dev/null +++ b/2.0/extensions/footnotes/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1"></a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'backref_symbol'     => '↩',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

backref_symbol

+ +

This string option sets the symbol used as the contents of the footnote backreference link. It defaults to \League\CommonMark\Extension\Footnote\Renderer\FootnoteBackrefRenderer::DEFAULT_SYMBOL = '↩'.

+ +

If you want to use a custom icon, set this to an empty string '' and take a look at the Adding Icons section below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ +

Adding Icons

+ +

You can use CSS to add a custom icon instead of providing a backref_symbol:

+ +
$config = [
+    'footnote' => [
+        'backref_class' => 'footnote-backref',
+        'backref_symbol' => '',
+    ],
+];
+
+ +

Then target the backref_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.footnote-backref::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/front-matter/index.html b/2.0/extensions/front-matter/index.html new file mode 100644 index 0000000000..30116ca566 --- /dev/null +++ b/2.0/extensions/front-matter/index.html @@ -0,0 +1,542 @@ + + + + + + + + + + + + + + + + + Front Matter Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Front Matter Extension

+ +

The FrontMatterExtension adds the ability to parse YAML front matter from the Markdown document and include that in the return result.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

You will also need to install symfony/yaml or the YAML extension for PHP to use this extension. For symfony/yaml:

+ +
composer require symfony/yaml
+
+ +

(You can use any version of symfony/yaml 2.3 or higher, though we recommend using 4.0 or higher.)

+ +

Front Matter Syntax

+ +

This extension follows the Jekyll Front Matter syntax. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:

+ +
---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+
+ +

This will produce a front matter array similar to this:

+ +
$parsedFrontMatter = [
+    'layout' => 'post',
+    'title' => 'I Love Markdown',
+    'tags' => [
+        'test',
+        'example',
+    ],
+];
+
+ +

And the HTML output will only contain the one heading:

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

Usage

+ +

Configure your Environment as usual and add the FrontMatterExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FrontMatterExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+// A sample Markdown file with some front matter:
+$markdown = <<<MD
+---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+MD;
+
+$result = $converter->convertToHtml($markdown);
+
+// Grab the front matter:
+if ($result instanceof RenderedContentWithFrontMatter) {
+    $frontMatter = $result->getFrontMatter();
+}
+
+// Output the HTML using any of these:
+echo $result;               // implicit string cast
+// or:
+echo (string) $result;      // explicit string cast
+// or:
+echo $result->getContent();
+
+ +

Parsing Front Matter Only

+ +

You don’t have to parse the entire file (including all the Markdown) if you only want the front matter. You can either instantiate the front matter parser yourself and call it directly, like this:

+ +
use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+// For `symfony/yaml`
+$frontMatterParser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
+// For YAML extension
+$frontMatterParser = new FrontMatterParser(new LibYamlFrontMatterParser());
+$result = $frontMatterParser->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

Or you can use the getFrontMatterParser() method from the extension:

+ +
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+$frontMatterExtension = new FrontMatterExtension();
+$result = $frontMatterExtension->getFrontMatterParser()->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

This latter approach may be more convenient if you have already instantiated a FrontMatterExtension object you’re adding to the Environment somewhere and just want to call that.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/github-flavored-markdown/index.html b/2.0/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..ec863f93ee --- /dev/null +++ b/2.0/extensions/github-flavored-markdown/index.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark and GFM parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/heading-permalinks/index.html b/2.0/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..a50c205150 --- /dev/null +++ b/2.0/extensions/heading-permalinks/index.html @@ -0,0 +1,608 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'content',
+        'fragment_prefix' => 'content',
+        'insert' => 'before',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

fragment_prefix

+ +

This should be a string you want prepended to the URL fragment in the link’s href attribute. This should typically be set to the same value as id_prefix for links to work properly. However, you may not want to expose that same prefix in your URLs - in that case, you can set this to something different (even an empty string) and use JavaScript to “rewrite” them.

+ +

For example, to emulate how GitHub heading permalinks work, set id_prefix to 'user-content', set fragment_prefix to '', and insert some JavaScript into the page like this:

+ +
var scrollToPermalink = function() {
+    var link = document.getElementById('user-content-' + window.location.hash);
+    if (link) {
+        link.scrollIntoView({behavior: 'smooth'});
+    }
+};
+
+window.addEventListener('hashchange', scrollToPermalink);
+if (window.location.hash) {
+    scrollToPermalink();
+}
+
+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

min_heading_level and max_heading_level

+ +

These two settings control which headings should have permalinks added. By default, all 6 levels (1, 2, 3, 4, 5, and 6) will have them. You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/inlines-only/index.html b/2.0/extensions/inlines-only/index.html new file mode 100644 index 0000000000..7ab4a2f0c3 --- /dev/null +++ b/2.0/extensions/inlines-only/index.html @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new, empty environment
+$environment = new Environment($config);
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/mentions/index.html b/2.0/extensions/mentions/index.html new file mode 100644 index 0000000000..f9d5c6b8fe --- /dev/null +++ b/2.0/extensions/mentions/index.html @@ -0,0 +1,666 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting prefix, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the first mention parser to
+        // successfully match and return a properly constructed Mention object (where the URL has been set) will be the
+        // the mention parser that is used. In this example, the GitHub handle would actually match first because
+        // there isn't any real validation to check whether https://www.github.com/colinodell exists. However, in
+        // CMS applications, you could check whether its a local user first, then check Twitter and then GitHub, etc.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Follow me on GitHub: @colinodell');
+// Output:
+// <p>Follow me on GitHub: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regular expression pattern (without opening/closing delimiter or modifiers), or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Inline\Element\AbstractInline;
+
+class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/overview/index.html b/2.0/extensions/overview/index.html new file mode 100644 index 0000000000..40542e9ae2 --- /dev/null +++ b/2.0/extensions/overview/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Default AttributesEasily apply default HTML classes using configuration options to match your site’s styles2.0.0 
Description ListsCreate <dl> description lists using Markdown Extra’s syntax2.0.0 
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
Front MatterParses YAML front matter from your Markdown input2.0.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the extensions you need
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the other extensions you need
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/smart-punctuation/index.html b/2.0/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..657ea78853 --- /dev/null +++ b/2.0/extensions/smart-punctuation/index.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/strikethrough/index.html b/2.0/extensions/strikethrough/index.html new file mode 100644 index 0000000000..a36493a1e6 --- /dev/null +++ b/2.0/extensions/strikethrough/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/table-of-contents/index.html b/2.0/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..79ea1e1f57 --- /dev/null +++ b/2.0/extensions/table-of-contents/index.html @@ -0,0 +1,597 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
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;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/tables/index.html b/2.0/extensions/tables/index.html new file mode 100644 index 0000000000..a1d222d448 --- /dev/null +++ b/2.0/extensions/tables/index.html @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/extensions/task-lists/index.html b/2.0/extensions/task-lists/index.html new file mode 100644 index 0000000000..9e6f977905 --- /dev/null +++ b/2.0/extensions/task-lists/index.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convertToHtml($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/index.html b/2.0/index.html new file mode 100644 index 0000000000..89b0d0a012 --- /dev/null +++ b/2.0/index.html @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello, World!')->getContent();
+
+// <h1>Hello, World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/installation/index.html b/2.0/installation/index.html new file mode 100644 index 0000000000..2c1f1f0d1c --- /dev/null +++ b/2.0/installation/index.html @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +
composer require "league/commonmark:^2.0"
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^2.0. This is equivalent to >=2.0 <3.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/security/index.html b/2.0/security/index.html new file mode 100644 index 0000000000..de84646be6 --- /dev/null +++ b/2.0/security/index.html @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/support/index.html b/2.0/support/index.html new file mode 100644 index 0000000000..c4b29ea275 --- /dev/null +++ b/2.0/support/index.html @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/upgrading/consumers/index.html b/2.0/upgrading/consumers/index.html new file mode 100644 index 0000000000..126377d78b --- /dev/null +++ b/2.0/upgrading/consumers/index.html @@ -0,0 +1,706 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.6 to 2.0 (for developers) - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Minimum PHP Version

+ +

The minimum supported PHP version was increased from 7.1 to 7.4.

+ +

CommonMarkConverter and GithubFlavoredMarkdownConverter constructors

+ +

The constructor methods for both CommonMarkConverter and GithubFlavoredMarkdownConverter no longer accept passing in a customized Environment. If you want to customize the extensions used in your converter you should switch to using MarkdownConverter. See the Basic Usage documentation for an example.

+ +
-use League\CommonMark\CommonMarkConverter;
+ use League\CommonMark\Environment\Environment;
+ use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+ use League\CommonMark\Extension\Table\TableExtension;
++use League\CommonMark\MarkdownConverter;
+ 
+ $config = [
+     'html_input' => 'escape',
+     'allow_unsafe_links' => false,
+     'max_nesting_level' => 100,
+ ];
+ 
+ 
+-$environment = new Environment();
++$environment = new Environment($config);
+ $environment->addExtension(new CommonMarkCoreExtension());
+ $environment->addExtension(new TableExtension());
+ 
+-$converter = new CommonMarkConverter($config, $environment); // or GithubFlavoredMarkdownConverter
++$converter = new MarkdownConverter($environment);
+ 
+ echo $converter->convertToHtml('Hello World!');
+
+ +

CommonMarkConverter Return Type

+ +

In 1.x, calling convertToHtml() would return a string. In 2.x this changed to return a RenderedContentInterface. To get the resulting HTML, either cast it to a string or call ->getContent(). (This new interface extends from Stringable so you can type hint against that instead, if needed.)

+ +
 use League\CommonMark\CommonMarkConverter;
+
+ $converter = new CommonMarkConverter();
+-echo $converter->convertToHtml('# Hello World!');
++echo $converter->convertToHtml('# Hello World!')->getContent();
++// or
++echo (string) $converter->convertToHtml('# Hello World!');
+
+ +

HTML Changes

+ +

Table of Contents items are no longer wrapped with <p> tags:

+ +
 <ul class="table-of-contents">
+     <li>
+-        <p><a href="#level-2-heading">Level 2 Heading</a></p>
++        <a href="#level-2-heading">Level 2 Heading</a>
+     </li>
+     <li>
+-        <p><a href="#level-4-heading">Level 4 Heading</a></p>
++        <a href="#level-4-heading">Level 4 Heading</a>
+     </li>
+     <li>
+-        <p><a href="#level-3-heading">Level 3 Heading</a></p>
++        <a href="#level-3-heading">Level 3 Heading</a>
+     </li>
+ </ul>
+
+ +

See #613 for details.

+ +

Additionally, the HTML (including URL fragments) for Heading Permalinks have changed:

+ +
-<h1><a id="user-content-hello-world" href="#hello-world" name="hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello World!</h1>
++<h1><a id="content-hello-world" href="#content-hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello World!</h1>
+
+ +

Note that the href now targets the id attribute instead of the name, which is deprecated in HTML 5. Additionally, the default prefix has changed to content. See the Heading Permalink extension documentation for more details on how to configure the prefixes.

+ +

Configuration Option Changes

+ +

Several configuration options now have new names:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Key/PathNew Key/PathNotes
enable_emcommonmark/enable_em 
enable_strongcommonmark/enable_strong 
use_asteriskcommonmark/use_asterisk 
use_underscorecommonmark/use_underscore 
unordered_list_markerscommonmark/unordered_list_markersEmpty arrays no longer allowed
heading_permalink/id_prefix(unchanged)Default is now content
heading_permalink/inner_contentsheading_permalink/symbol 
heading_permalink/slug_normalizerslug_normalizer/instance 
max_nesting_level(unchanged)Only integer values are supported
mentions/*/symbolmentions/*/prefix 
mentions/*/regexmentions/*/patternCannot contain start/end / delimiters
+ +

Classes/Namespaces Renamed

+ +

Many classes now live in different namespaces, and some have also been renamed. Here’s a quick guide showing their new locations:

+ +

(Note that the base namespace of League\CommonMark has been omitted from this table for brevity.)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Class Namespace/Name (1.x)New Class Namespace/Name (2.0)
EnvironmentEnvironment\Environment
Extension\CommonMarkCoreExtensionExtension\CommonMark\CommonMarkCoreExtension
Block\Element\DocumentNode\Block\Document
DocParserParser\MarkdownParser
DocParserInterfaceParser\MarkdownParserInterface
ElementRendererInterfaceRenderer\ChildNodeRendererInterface
HtmlRendererRenderer\HtmlRenderer
+ +

(This is only a partial list of the clases and interfaces you’re likely to work with as a consumer – see the developer upgrade guide for the complete list.)

+ +

Removed Classes

+ +

The following classes have been removed:

+ + + + + + + + + + + + + + + + + + +
Class name in 1.xReplacement / Notes
ConverterUse MarkdownConverter instead.
ConverterInterfaceUse MarkdownConverterInterface. This interface has the same methods so it should be a drop-in replacement.
+ +

(Several other classes were removed, but these are the only ones you’re likely to notice. See the developer upgrade guide for the complete list.)

+ +

Renamed constants

+ +

The following constants have been moved/renamed:

+ + + + + + + + + + + + + + + + + + + + + + +
Old Name/Location (1.x)New Name/Location (2.0)
EnvironmentInterface::HTML_INPUT_ALLOWHtmlFilter::ALLOW
EnvironmentInterface::HTML_INPUT_ESCAPEHtmlFilter::ESCAPE
EnvironmentInterface::HTML_INPUT_STRIPHtmlFilter::STRIP
+ +

Renamed Methods

+ +

The following methods have been renamed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassOld Name (1.x)New Name (2.0)
Environment / ConfigurableEnvironmentInterfaceaddBlockParser()addBlockStartParser()
ReferenceMap / ReferenceMapInterfaceaddReference()add()
ReferenceMap / ReferenceMapInterfacegetReference()get()
ReferenceMap / ReferenceMapInterfacelistReferences()getIterator()
+ +

Configuration Method Changes

+ +

Calling EnvironmentInterface::getConfig() without any parameters is no longer supported.

+ +

Calling ConfigurableEnvironmentInterface::mergeConfig() without any parameters is no longer supported.

+ +

The ConfigurableEnvironmentInterface::setConfig() method has been removed. Use getConfig() instead.

+ +

bin/commonmark command

+ +

This command was buggy to test and was relatively unpopular, so it has been removed. If you need this type of functionality, consider writing your own script with a Converter/Environment configured exactly how you want it.

+ +

CommonMarkConverter::VERSION constant

+ +

This previously-deprecated constant was removed in 2.0. Use \Composer\InstalledVersions provided by composer-runtime-api instead.

+ +

HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant

+ +

This previously-deprecated constant was removed in 2.0. Use HeadingPermalinkRenderer::DEFAULT_SYMBOL instead.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/upgrading/developers/index.html b/2.0/upgrading/developers/index.html new file mode 100644 index 0000000000..ee6d61a907 --- /dev/null +++ b/2.0/upgrading/developers/index.html @@ -0,0 +1,1348 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.6 to 2.0 (for developers) - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Minimum PHP Version

+ +

The minimum supported PHP version was increased from 7.1 to 7.4.

+ +

CommonMarkConverter and GithubFlavoredMarkdownConverter constructors

+ +

The constructor methods for both CommonMarkConverter and GithubFlavoredMarkdownConverter no longer accept passing in a customized Environment. If you want to customize the extensions used in your converter you should switch to using MarkdownConverter. See the Basic Usage documentation for an example.

+ +
-use League\CommonMark\CommonMarkConverter;
+ use League\CommonMark\Environment\Environment;
+ use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+ use League\CommonMark\Extension\Table\TableExtension;
++use League\CommonMark\MarkdownConverter;
+ 
+ $config = [
+     'html_input' => 'escape',
+     'allow_unsafe_links' => false,
+     'max_nesting_level' => 100,
+ ];
+ 
+-$environment = new Environment();
++$environment = new Environment($config);
+ $environment->addExtension(new CommonMarkCoreExtension());
+ $environment->addExtension(new TableExtension());
+ 
+-$converter = new CommonMarkConverter($config, $environment); // or GithubFlavoredMarkdownConverter
++$converter = new MarkdownConverter($environment);
+ 
+ echo $converter->convertToHtml('Hello World!');
+
+ +

CommonMarkConverter Return Type

+ +

In 1.x, calling convertToHtml() would return a string. In 2.x this changed to return a RenderedContentInterface. To get the resulting HTML, either cast the return value to a string or call ->getContent(). (This new interface extends from Stringable so you can type hint against that instead, if needed.)

+ +
 use League\CommonMark\CommonMarkConverter;
+
+ $converter = new CommonMarkConverter();
+-echo $converter->convertToHtml('# Hello World!');
++echo $converter->convertToHtml('# Hello World!')->getContent();
++// or
++echo (string) $converter->convertToHtml('# Hello World!');
+
+ +

HTML Changes

+ +

Table of Contents items are no longer wrapped with <p> tags:

+ +
 <ul class="table-of-contents">
+     <li>
+-        <p><a href="#level-2-heading">Level 2 Heading</a></p>
++        <a href="#level-2-heading">Level 2 Heading</a>
+     </li>
+     <li>
+-        <p><a href="#level-4-heading">Level 4 Heading</a></p>
++        <a href="#level-4-heading">Level 4 Heading</a>
+     </li>
+     <li>
+-        <p><a href="#level-3-heading">Level 3 Heading</a></p>
++        <a href="#level-3-heading">Level 3 Heading</a>
+     </li>
+ </ul>
+
+ +

See #613 for details.

+ +

Additionally, the HTML (including URL fragments) for Heading Permalinks have changed:

+ +
-<h1><a id="user-content-hello-world" href="#hello-world" name="hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello World!</h1>
++<h1><a id="content-hello-world" href="#content-hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello World!</h1>
+
+ +

Note that the href now targets the id attribute instead of the name, which is deprecated in HTML 5. Additionally, the default prefix has changed to content. See the Heading Permalink extension documentation for more details on how to configure the prefixes.

+ +

Configuration Option Changes

+ +

Several configuration options now have new names:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Key/PathNew Key/PathNotes
enable_emcommonmark/enable_em 
enable_strongcommonmark/enable_strong 
use_asteriskcommonmark/use_asterisk 
use_underscorecommonmark/use_underscore 
unordered_list_markerscommonmark/unordered_list_markersEmpty arrays no longer allowed
heading_permalink/id_prefix(unchanged)Default is now content
heading_permalink/inner_contentsheading_permalink/symbol 
heading_permalink/slug_normalizerslug_normalizer/instance 
max_nesting_level(unchanged)Only integer values are supported
mentions/*/symbolmentions/*/prefix 
mentions/*/regexmentions/*/patternCannot contain start/end / delimiters
+ +

Method Return Types

+ +

Return types have been added to virtually all class and interface methods. If you implement or extend anything from this library, ensure you also have the proper return types added.

+ +

Configuration Classes Relocated

+ +

The following classes have been moved to the league/config package:

+ + + + + + + + + + + + + + + + + + + + + + +
Old Class Namespace/Name (1.x)Moved To
League\CommonMark\Util\ConfigurationAwareInterfaceLeague\Config\ConfigurationAwareInterface
League\CommonMark\Util\ConfigurationInterfaceLeague\Config\ConfigurationInterface
League\CommonMark\Util\ConfigurationLeague\Config\Configuration
+ +

Classes/Namespaces Renamed

+ +

Many classes now live in different namespaces, and some have also been renamed. Here’s a quick guide showing their new locations:

+ +

(Note that the base namespace of League\CommonMark has been omitted from this table for brevity.)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Class Namespace/Name (1.x)New Class Namespace/Name (2.0)
ConfigurableEnvironmentInterfaceEnvironment\ConfigurableEnvironmentInterface
EnvironmentAwareInterfaceEnvironment\EnvironmentAwareInterface
EnvironmentEnvironment\Environment
EnvironmentInterfaceEnvironment\EnvironmentInterface
Extension\CommonMarkCoreExtensionExtension\CommonMark\CommonMarkCoreExtension
Delimiter\Processor\EmphasisDelimiterProcessorExtension\CommonMark\Delimiter\Processor\EmphasisDelimiterProcessor
Block\Element\BlockQuoteExtension\CommonMark\Node\Block\BlockQuote
Block\Element\FencedCodeExtension\CommonMark\Node\Block\FencedCode
Block\Element\HeadingExtension\CommonMark\Node\Block\Heading
Block\Element\HtmlBlockExtension\CommonMark\Node\Block\HtmlBlock
Block\Element\IndentedCodeExtension\CommonMark\Node\Block\IndentedCode
Block\Element\ListBlockExtension\CommonMark\Node\Block\ListBlock
Block\Element\ListDataExtension\CommonMark\Node\Block\ListData
Block\Element\ListItemExtension\CommonMark\Node\Block\ListItem
Block\Element\ThematicBreakExtension\CommonMark\Node\Block\ThematicBreak
Inline\Element\AbstractWebResourceExtension\CommonMark\Node\Inline\AbstractWebResource
Inline\Element\CodeExtension\CommonMark\Node\Inline\Code
Inline\Element\EmphasisExtension\CommonMark\Node\Inline\Emphasis
Inline\Element\HtmlInlineExtension\CommonMark\Node\Inline\HtmlInline
Inline\Element\ImageExtension\CommonMark\Node\Inline\Image
Inline\Element\LinkExtension\CommonMark\Node\Inline\Link
Inline\Element\StrongExtension\CommonMark\Node\Inline\Strong
Block\Parser\BlockQuoteParserExtension\CommonMark\Parser\Block\BlockQuoteParser
Block\Parser\FencedCodeParserExtension\CommonMark\Parser\Block\FencedCodeParser
Block\Parser\ATXHeadingParser and Block\Parser\SetExtHeadingParserExtension\CommonMark\Parser\Block\HeadingParser
Block\Parser\HtmlBlockParserExtension\CommonMark\Parser\Block\HtmlBlockParser
Block\Parser\IndentedCodeParserExtension\CommonMark\Parser\Block\IndentedCodeParser
Block\Parser\ListParserExtension\CommonMark\Parser\Block\ListParser
Block\Parser\ThematicBreakParserExtension\CommonMark\Parser\Block\ThematicBreakParser
Inline\Parser\AutolinkParserExtension\CommonMark\Parser\Inline\AutolinkParser
Inline\Parser\BacktickParserExtension\CommonMark\Parser\Inline\BacktickParser
Inline\Parser\BangParserExtension\CommonMark\Parser\Inline\BangParser
Inline\Parser\CloseBracketParserExtension\CommonMark\Parser\Inline\CloseBracketParser
Inline\Parser\EntityParserExtension\CommonMark\Parser\Inline\EntityParser
Inline\Parser\EscapableParserExtension\CommonMark\Parser\Inline\EscapableParser
Inline\Parser\HtmlInlineParserExtension\CommonMark\Parser\Inline\HtmlInlineParser
Inline\Parser\OpenBracketParserExtension\CommonMark\Parser\Inline\OpenBracketParser
Block\Renderer\BlockQuoteRendererExtension\CommonMark\Renderer\Block\BlockQuoteRenderer
Block\Renderer\FencedCodeRendererExtension\CommonMark\Renderer\Block\FencedCodeRenderer
Block\Renderer\HeadingRendererExtension\CommonMark\Renderer\Block\HeadingRenderer
Block\Renderer\HtmlBlockRendererExtension\CommonMark\Renderer\Block\HtmlBlockRenderer
Block\Renderer\IndentedCodeRendererExtension\CommonMark\Renderer\Block\IndentedCodeRenderer
Block\Renderer\ListBlockRendererExtension\CommonMark\Renderer\Block\ListBlockRenderer
Block\Renderer\ListItemRendererExtension\CommonMark\Renderer\Block\ListItemRenderer
Block\Renderer\ThematicBreakRendererExtension\CommonMark\Renderer\Block\ThematicBreakRenderer
Inline\Renderer\CodeRendererExtension\CommonMark\Renderer\Inline\CodeRenderer
Inline\Renderer\EmphasisRendererExtension\CommonMark\Renderer\Inline\EmphasisRenderer
Inline\Renderer\HtmlInlineRendererExtension\CommonMark\Renderer\Inline\HtmlInlineRenderer
Inline\Renderer\ImageRendererExtension\CommonMark\Renderer\Inline\ImageRenderer
Inline\Renderer\LinkRendererExtension\CommonMark\Renderer\Inline\LinkRenderer
Inline\Renderer\StrongRendererExtension\CommonMark\Renderer\Inline\StrongRenderer
Extension\SmartPunct\PunctuationParserExtension\SmartPunct\DashParser and Extension\SmartPunct\EllipsesParser
Extension\TableOfContents\TableOfContentsExtension\TableOfContents\Node\TableOfContents
Block\Element\AbstractBlockNode\Block\AbstractBlock
Block\Element\DocumentNode\Block\Document
Block\Element\InlineContainerInterfaceNode\Block\InlineContainerInterface
Block\Element\ParagraphNode\Block\Paragraph
Block\Element\StringContainerInterfaceNode\StringContainerInterface
Inline\Element\AbstractInlineNode\Inline\AbstractInline
Inline\Element\AbstractStringContainerNode\Inline\AbstractStringContainer
Inline\AdjacentTextMergerNode\Inline\AdjacentTextMerger
Inline\Element\NewlineNode\Inline\Newline
Inline\Element\TextNode\Inline\Text
Block\Parser\BlockParserInterfaceParser\Block\BlockContinueParserInterface and Parser\Block\BlockStartParserInterface
Block\Parser\LazyParagraphParserParser\Block\ParagraphParser
CursorParser\Cursor
DocParserParser\MarkdownParser
DocParserInterfaceParser\MarkdownParserInterface
Inline\Parser\InlineParserInterfaceParser\Inline\InlineParserInterface
Inline\Parser\NewlineParserParser\Inline\NewlineParser
InlineParserContextParser\InlineParserContext
InlineParserEngineParser\InlineParserEngine
Block\Renderer\DocumentRendererRenderer\Block\DocumentRenderer
Block\Renderer\ParagraphRendererRenderer\Block\ParagraphRenderer
ElementRendererInterfaceRenderer\ChildNodeRendererInterface
HtmlRendererRenderer\HtmlRenderer
Inline\Renderer\NewlineRendererRenderer\Inline\NewlineRenderer
Inline\Renderer\TextRendererRenderer\Inline\TextRenderer
Block\Renderer\BlockRendererInterface and Inline\Renderer\InlineRendererInterfaceRenderer\NodeRendererInterface
HtmlElementUtil\HtmlElement
+ +

New Block Parsing Approach

+ +

We’ve completely changed how block parsing works in 2.0. In a nutshell, 1.x had parsing responsibilities split between +the parser and the node. But nodes should be “dumb” and not know anything about how they are parsed - they should only +know the bare minimum needed for rendering.

+ +

As a result, 2.x has delegated the parsing responsibilities to two different interfaces:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResponsibilityOld Method (1.x)New Method (2.0)
Identifying the start of a blockBlockParserInterface::parse()BlockStartParserInterface::tryStart()
Instantiating and configuring the new blockBlockParserInterface::parse()BlockContinueParserInterface::__construct()
Determining if the block acts as a containerAbstractBlock::isContainer()BlockContinueParserInterface::isContainer()
Determining if the block can have lazy continuation linesAbstractBlock::isCode()BlockContinueParserInterface::canHaveLazyContinuationLines()
Determining if the block can contain certain child blocksAbstractBlock::canContain()BlockContinueParserInterface::canContain()
Determining if the block continues on the next lineAbstractBlock::matchesNextLine()BlockContinueParserInterface::tryContinue()
Adding the next line to the blockAbstractBlock::handleRemainingContents()BlockContinueParserInterface::addLine()
Finalizing the block and its contentsAbstractBlock::finalize()BlockContinueParserInterface::closeBlock()
+ +

As a result of making this change, the addBlockParser() method on ConfigurableEnvironmentInterface has changed to addBlockStartParser().

+ +

See the block parsing documentation for more information on this new approach.

+ +

New Inline Parsing Approach

+ +

The getCharacters() method on InlineParserInterface has been replaced with a more-robust getMatchDefinition() method which allows your parser to match against more than just single characters. All custom inline parsers will need to change to this new approach.

+ +

Additionally, when the parse() method is called, the Cursor is no longer proactively advanced past the matching character/start position for you. You’ll need to advance this yourself. However, the InlineParserContext now provides the fully-matched text and its length, allowing you to easily advanceBy() the cursor without having to do an expensive $cursor->match() yourself which is a nice performance optimization.

+ +

See the inline parsing documentation for more information on this new approach.

+ +

Rendering Changes

+ +

This library no longer differentiates between block renderers and inline renderers - everything now uses “node renderers” which allow us to have a unified approach to rendering! As a result, the following changes were made, which you may need to change in your custom extensions:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Method/Interface (1.x)New Method/Interface (2.0)
BlockRendererInterfaceNodeRendererInterface
InlineRendererInterfaceNodeRendererInterface
EnvironmentInterface::getBlockRenderersForClass()EnvironmentInterface::getRenderersForClass()
EnvironmentInterface::getInlineRenderersForClass()EnvironmentInterface::getRenderersForClass()
ConfigurableEnvironmentInterface::addBlockRenderer()ConfigurableEnvironmentInterface::addRenderer()
ConfigurableEnvironmentInterface::addInlineRenderer()ConfigurableEnvironmentInterface::addRenderer()
ElementRendererInterface::renderBlock()ChildNodeRendererInterface::renderNodes()
ElementRendererInterface::renderBlocks()ChildNodeRendererInterface::renderNodes()
ElementRendererInterface::renderInline()ChildNodeRendererInterface::renderNodes()
ElementRendererInterface::renderInlines()ChildNodeRendererInterface::renderNodes()
HtmlRenderer::renderBlock($document)HtmlRenderer::renderDocument()
+ +

Renderers now implement the unified NodeRendererInterface which has a similar (but slightly different) signature from +the old BlockRendererInterface and InlineRendererInterface interfaces:

+ +
/**
+ * @param Node                       $node
+ * @param ChildNodeRendererInterface $childRenderer
+ *
+ * @return HtmlElement|string|null
+ */
+public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The element being rendered is still passed in the first argument, and the object that helps you render children is still +passed in the second argument. Note that blocks are no longer told whether they’re being rendered in a tight list - if you +need to know about this, traverse up the $node AST yourself and check any ListBlock ancestor for tightness.

+ +

AST Node Changes

+ +

The AbstractBlock::$data and AbstractInline::$data arrays were replaced with a Data array-like object on the base Node class.

+ +

Removed Classes

+ +

The following classes have been removed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Class name in 1.xReplacement / Notes
AbstractStringContainerBlockUse extends AbstractBlock implements StringContainerInterface instead. Note the new method names.
ContextUse MarkdownParserState instead (has different methods but serves a similar purpose)
ContextInterfaceUse MarkdownParserStateInterface instead (has different methods but serves a similar purpose)
ConverterUse MarkdownConverter instead.
ConverterInterfaceUse MarkdownConverterInterface. This interface has the same methods so it should be a drop-in replacement.
UnmatchedBlockCloserNo longer needed 2.x
+ +

Renamed constants

+ +

The following constants have been moved/renamed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Name/Location (1.x)New Name/Location (2.0)
EnvironmentInterface::HTML_INPUT_ALLOWHtmlFilter::ALLOW
EnvironmentInterface::HTML_INPUT_ESCAPEHtmlFilter::ESCAPE
EnvironmentInterface::HTML_INPUT_STRIPHtmlFilter::STRIP
TableCell::TYPE_HEADTableCell::TYPE_HEADER
TableCell::TYPE_BODYTableCell::TYPE_DATA
+ +

Renamed Methods

+ +

The following methods have been renamed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassOld Name (1.x)New Name (2.0)
Environment / ConfigurableEnvironmentInterfaceaddBlockParser()addBlockStartParser()
ReferenceMap / ReferenceMapInterfaceaddReference()add()
ReferenceMap / ReferenceMapInterfacegetReference()get()
ReferenceMap / ReferenceMapInterfacelistReferences()getIterator()
+ +

Visibility Changes

+ +

The following properties have had their visibility changed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyWas (1.x)Is Now (2.0)Notes
TableCell::$alignpublicprivateUse getAlign() and setAlign() instead
TableCell::$typepublicprivateUse getType() and setType() instead
TableSection::$typepublicprivateUse getType() instead
+ +

Configuration Method Changes

+ +

Calling EnvironmentInterface::getConfig() without any parameters is no longer supported.

+ +

Calling ConfigurableEnvironmentInterface::mergeConfig() without any parameters is no longer supported.

+ +

The ConfigurableEnvironmentInterface::setConfig() method has been removed. Use getConfig() instead.

+ +

New approach to the ReferenceParser

+ +

The ReferenceParser class in 1.x worked on complete paragraphs of text. This has been changed in 2.x to work in a more-gradual fashion, where parsing is done on-the-fly as new lines are added. +Whereas you may have previously called parse() on a Cursor once on something containing multiple lines, you should now call parse() on each line of text and then later call getReferences() +to check what has been parsed.

+ +

Html5Entities utility class removed

+ +

Use the Html5EntityDecoder utility class instead.

+ +

bin/commonmark command

+ +

This command was buggy to test and was relatively unpopular, so it has been removed. If you need this type of functionality, consider writing your own script with a Converter/Environment configured exactly how you want it.

+ +

CommonMarkConverter::VERSION constant

+ +

This previously-deprecated constant was removed in 2.0 Use \Composer\InstalledVersions provided by composer-runtime-api instead.

+ +

HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant

+ +

This previously-deprecated constant was removed in 2.0. Use HeadingPermalinkRenderer::DEFAULT_SYMBOL instead.

+ +

ArrayCollection changes

+ +

Several methods were removed from this class - here are the methods along with possible alternatives you can switch to:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Removed Method NameAlternative
add($value)$collection[] = $value
set($key, $value)$collection[$key] = $value
get($key)$collection[$key]
remove($key)unset($collection[$key])
isEmpty()count($collection) === 0
contains($value)in_array($value, $collection->toArray(), true)
indexOf($value)array_search($value, $collection->toArray(), true)
containsKey($key)isset($collection[$key])
replaceWith()(none provided)
removeGaps()(none provided)
+ +

This class is also final now, so don’t extend it.

+ +

final classes

+ +

The following classes are now marked final and cannot be extended:

+ + + +

Node setter methods return void

+ +

All set*() methods on all Node types now return void (whereas some used to return $this in 1.x) for consistency.

+ +

Unused methods

+ +

The following unused methods have been removed:

+ + + +

Slug Normalizer

+ +

Need to generate unique slugs in your extensions? Use the new Slug Normalizer provided by the Environment.

+ +

Text Normalizers

+ +

The second argument to TextNormalizerInterface::normalize() used to allow any arbitrary object. This was changed to an array so that multiple things can be passed in at once.

+ + + +

The title attribute for Link and Image nodes is now stored using a dedicated property instead of stashing it in $data. Use getTitle() and setTitle() to access the value.

+ +

Node Iteration

+ +

In 1.x, most custom code used $node->walker() to iterate the AST. Although this still exists, consider whether your code could use $node->iterator() instead which can be up to twice as fast!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/upgrading/index.html b/2.0/upgrading/index.html new file mode 100644 index 0000000000..6242ec2e73 --- /dev/null +++ b/2.0/upgrading/index.html @@ -0,0 +1,421 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.6 to 2.0 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 1.6 to 2.0

+ +

Version 2.0 contains lots of changes throughout the library. We’ve split the upgrade guide into three sections to help you better identify the changes that are most relevant to you:

+ +

For Consumers

+ +

The upgrade guide for consumers is relevant for developers who use this library as-is to perform basic conversion of Markdown to HTML. You might enable some extensions or tweak the configuration settings, but you don’t write your own custom parsers or anything like that. This condensed upgrade guide therefore only covers the most obvious changes that might impact your usage of this library.

+ +

For Integrators

+ +

If you develop open-source software that uses this library, read the upgrade guide for integrators. It contains all of the information from the Consumer guide above, but with additional details that may be relevant to you.

+ +

For Developers

+ +

The upgrade guide for developers is aimed at developers who create custom extensions/parsers/renderers and need to know about all of the under-the-hood changes in 2.x. It is the most comprehensive guide, containing all of the information from the two guides above, and even more details about the under-the-hood changes that likely impact your customizations.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/upgrading/integrators/index.html b/2.0/upgrading/integrators/index.html new file mode 100644 index 0000000000..9351be3ed2 --- /dev/null +++ b/2.0/upgrading/integrators/index.html @@ -0,0 +1,1117 @@ + + + + + + + + + + + + + + + + + Upgrading from 1.6 to 2.0 (for integrators) - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

Minimum PHP Version

+ +

The minimum supported PHP version was increased from 7.1 to 7.4.

+ +

CommonMarkConverter and GithubFlavoredMarkdownConverter constructors

+ +

The constructor methods for both CommonMarkConverter and GithubFlavoredMarkdownConverter no longer accept passing in a customized Environment. If you want to customize the extensions used in your converter you should switch to using MarkdownConverter. See the Basic Usage documentation for an example.

+ +
-use League\CommonMark\CommonMarkConverter;
+ use League\CommonMark\Environment\Environment;
+ use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+ use League\CommonMark\Extension\Table\TableExtension;
++use League\CommonMark\MarkdownConverter;
+ 
+ $config = [
+     'html_input' => 'escape',
+     'allow_unsafe_links' => false,
+     'max_nesting_level' => 100,
+ ];
+ 
+-$environment = new Environment();
++$environment = new Environment($config);
+ $environment->addExtension(new CommonMarkCoreExtension());
+ $environment->addExtension(new TableExtension());
+ 
+-$converter = new CommonMarkConverter($config, $environment); // or GithubFlavoredMarkdownConverter
++$converter = new MarkdownConverter($environment);
+ 
+ echo $converter->convertToHtml('Hello World!');
+
+ +

CommonMarkConverter Return Type

+ +

In 1.x, calling convertToHtml() would return a string. In 2.x this changed to return a RenderedContentInterface. To get the resulting HTML, either cast the return value to a string or call ->getContent(). (This new interface extends from Stringable so you can type hint against that instead, if needed.)

+ +
 use League\CommonMark\CommonMarkConverter;
+
+ $converter = new CommonMarkConverter();
+-echo $converter->convertToHtml('# Hello World!');
++echo $converter->convertToHtml('# Hello World!')->getContent();
++// or
++echo (string) $converter->convertToHtml('# Hello World!');
+
+ +

HTML Changes

+ +

Table of Contents items are no longer wrapped with <p> tags:

+ +
 <ul class="table-of-contents">
+     <li>
+-        <p><a href="#level-2-heading">Level 2 Heading</a></p>
++        <a href="#level-2-heading">Level 2 Heading</a>
+     </li>
+     <li>
+-        <p><a href="#level-4-heading">Level 4 Heading</a></p>
++        <a href="#level-4-heading">Level 4 Heading</a>
+     </li>
+     <li>
+-        <p><a href="#level-3-heading">Level 3 Heading</a></p>
++        <a href="#level-3-heading">Level 3 Heading</a>
+     </li>
+ </ul>
+
+ +

See #613 for details.

+ +

Additionally, the HTML (including URL fragments) for Heading Permalinks have changed:

+ +
-<h1><a id="user-content-hello-world" href="#hello-world" name="hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello World!</h1>
++<h1><a id="content-hello-world" href="#content-hello-world" class="heading-permalink" aria-hidden="true" title="Permalink">¶</a>Hello World!</h1>
+
+ +

Note that the href now targets the id attribute instead of the name, which is deprecated in HTML 5. Additionally, the default prefix has changed to content. See the Heading Permalink extension documentation for more details on how to configure the prefixes.

+ +

Configuration Option Changes

+ +

Several configuration options now have new names:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Key/PathNew Key/PathNotes
enable_emcommonmark/enable_em 
enable_strongcommonmark/enable_strong 
use_asteriskcommonmark/use_asterisk 
use_underscorecommonmark/use_underscore 
unordered_list_markerscommonmark/unordered_list_markersEmpty arrays no longer allowed
heading_permalink/id_prefix(unchanged)Default is now content
heading_permalink/inner_contentsheading_permalink/symbol 
heading_permalink/slug_normalizerslug_normalizer/instance 
max_nesting_level(unchanged)Only integer values are supported
mentions/*/symbolmentions/*/prefix 
mentions/*/regexmentions/*/patternCannot contain start/end / delimiters
+ +

Method Return Types

+ +

Return types have been added to virtually all class and interface methods. If you implement or extend anything from this library, ensure you also have the proper return types added.

+ +

Configuration Classes Relocated

+ +

The following classes have been moved to the league/config package:

+ + + + + + + + + + + + + + + + + + + + + + +
Old Class Namespace/Name (1.x)Moved To
League\CommonMark\Util\ConfigurationAwareInterfaceLeague\Config\ConfigurationAwareInterface
League\CommonMark\Util\ConfigurationInterfaceLeague\Config\ConfigurationInterface
League\CommonMark\Util\ConfigurationLeague\Config\Configuration
+ +

Classes/Namespaces Renamed

+ +

Many classes now live in different namespaces, and some have also been renamed. Here’s a quick guide showing their new locations:

+ +

(Note that the base namespace of League\CommonMark has been omitted from this table for brevity.)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Class Namespace/Name (1.x)New Class Namespace/Name (2.0)
ConfigurableEnvironmentInterfaceEnvironment\ConfigurableEnvironmentInterface
EnvironmentAwareInterfaceEnvironment\EnvironmentAwareInterface
EnvironmentEnvironment\Environment
EnvironmentInterfaceEnvironment\EnvironmentInterface
Extension\CommonMarkCoreExtensionExtension\CommonMark\CommonMarkCoreExtension
Delimiter\Processor\EmphasisDelimiterProcessorExtension\CommonMark\Delimiter\Processor\EmphasisDelimiterProcessor
Block\Element\BlockQuoteExtension\CommonMark\Node\Block\BlockQuote
Block\Element\FencedCodeExtension\CommonMark\Node\Block\FencedCode
Block\Element\HeadingExtension\CommonMark\Node\Block\Heading
Block\Element\HtmlBlockExtension\CommonMark\Node\Block\HtmlBlock
Block\Element\IndentedCodeExtension\CommonMark\Node\Block\IndentedCode
Block\Element\ListBlockExtension\CommonMark\Node\Block\ListBlock
Block\Element\ListDataExtension\CommonMark\Node\Block\ListData
Block\Element\ListItemExtension\CommonMark\Node\Block\ListItem
Block\Element\ThematicBreakExtension\CommonMark\Node\Block\ThematicBreak
Inline\Element\AbstractWebResourceExtension\CommonMark\Node\Inline\AbstractWebResource
Inline\Element\CodeExtension\CommonMark\Node\Inline\Code
Inline\Element\EmphasisExtension\CommonMark\Node\Inline\Emphasis
Inline\Element\HtmlInlineExtension\CommonMark\Node\Inline\HtmlInline
Inline\Element\ImageExtension\CommonMark\Node\Inline\Image
Inline\Element\LinkExtension\CommonMark\Node\Inline\Link
Inline\Element\StrongExtension\CommonMark\Node\Inline\Strong
Block\Parser\BlockQuoteParserExtension\CommonMark\Parser\Block\BlockQuoteParser
Block\Parser\FencedCodeParserExtension\CommonMark\Parser\Block\FencedCodeParser
Block\Parser\ATXHeadingParser and Block\Parser\SetExtHeadingParserExtension\CommonMark\Parser\Block\HeadingParser
Block\Parser\HtmlBlockParserExtension\CommonMark\Parser\Block\HtmlBlockParser
Block\Parser\IndentedCodeParserExtension\CommonMark\Parser\Block\IndentedCodeParser
Block\Parser\ListParserExtension\CommonMark\Parser\Block\ListParser
Block\Parser\ThematicBreakParserExtension\CommonMark\Parser\Block\ThematicBreakParser
Inline\Parser\AutolinkParserExtension\CommonMark\Parser\Inline\AutolinkParser
Inline\Parser\BacktickParserExtension\CommonMark\Parser\Inline\BacktickParser
Inline\Parser\BangParserExtension\CommonMark\Parser\Inline\BangParser
Inline\Parser\CloseBracketParserExtension\CommonMark\Parser\Inline\CloseBracketParser
Inline\Parser\EntityParserExtension\CommonMark\Parser\Inline\EntityParser
Inline\Parser\EscapableParserExtension\CommonMark\Parser\Inline\EscapableParser
Inline\Parser\HtmlInlineParserExtension\CommonMark\Parser\Inline\HtmlInlineParser
Inline\Parser\OpenBracketParserExtension\CommonMark\Parser\Inline\OpenBracketParser
Block\Renderer\BlockQuoteRendererExtension\CommonMark\Renderer\Block\BlockQuoteRenderer
Block\Renderer\FencedCodeRendererExtension\CommonMark\Renderer\Block\FencedCodeRenderer
Block\Renderer\HeadingRendererExtension\CommonMark\Renderer\Block\HeadingRenderer
Block\Renderer\HtmlBlockRendererExtension\CommonMark\Renderer\Block\HtmlBlockRenderer
Block\Renderer\IndentedCodeRendererExtension\CommonMark\Renderer\Block\IndentedCodeRenderer
Block\Renderer\ListBlockRendererExtension\CommonMark\Renderer\Block\ListBlockRenderer
Block\Renderer\ListItemRendererExtension\CommonMark\Renderer\Block\ListItemRenderer
Block\Renderer\ThematicBreakRendererExtension\CommonMark\Renderer\Block\ThematicBreakRenderer
Inline\Renderer\CodeRendererExtension\CommonMark\Renderer\Inline\CodeRenderer
Inline\Renderer\EmphasisRendererExtension\CommonMark\Renderer\Inline\EmphasisRenderer
Inline\Renderer\HtmlInlineRendererExtension\CommonMark\Renderer\Inline\HtmlInlineRenderer
Inline\Renderer\ImageRendererExtension\CommonMark\Renderer\Inline\ImageRenderer
Inline\Renderer\LinkRendererExtension\CommonMark\Renderer\Inline\LinkRenderer
Inline\Renderer\StrongRendererExtension\CommonMark\Renderer\Inline\StrongRenderer
Extension\SmartPunct\PunctuationParserExtension\SmartPunct\DashParser and Extension\SmartPunct\EllipsesParser
Extension\TableOfContents\TableOfContentsExtension\TableOfContents\Node\TableOfContents
Block\Element\AbstractBlockNode\Block\AbstractBlock
Block\Element\DocumentNode\Block\Document
Block\Element\InlineContainerInterfaceNode\Block\InlineContainerInterface
Block\Element\ParagraphNode\Block\Paragraph
Block\Element\StringContainerInterfaceNode\StringContainerInterface
Inline\Element\AbstractInlineNode\Inline\AbstractInline
Inline\Element\AbstractStringContainerNode\Inline\AbstractStringContainer
Inline\AdjacentTextMergerNode\Inline\AdjacentTextMerger
Inline\Element\NewlineNode\Inline\Newline
Inline\Element\TextNode\Inline\Text
Block\Parser\BlockParserInterfaceParser\Block\BlockContinueParserInterface and Parser\Block\BlockStartParserInterface
Block\Parser\LazyParagraphParserParser\Block\ParagraphParser
CursorParser\Cursor
DocParserParser\MarkdownParser
DocParserInterfaceParser\MarkdownParserInterface
Inline\Parser\InlineParserInterfaceParser\Inline\InlineParserInterface
Inline\Parser\NewlineParserParser\Inline\NewlineParser
InlineParserContextParser\InlineParserContext
InlineParserEngineParser\InlineParserEngine
Block\Renderer\DocumentRendererRenderer\Block\DocumentRenderer
Block\Renderer\ParagraphRendererRenderer\Block\ParagraphRenderer
ElementRendererInterfaceRenderer\ChildNodeRendererInterface
HtmlRendererRenderer\HtmlRenderer
Inline\Renderer\NewlineRendererRenderer\Inline\NewlineRenderer
Inline\Renderer\TextRendererRenderer\Inline\TextRenderer
Block\Renderer\BlockRendererInterface and Inline\Renderer\InlineRendererInterfaceRenderer\NodeRendererInterface
HtmlElementUtil\HtmlElement
+ +

Most of these won’t be relevant unless your integration allows people to add/remove extensions, parsers, etc. and you might reference those classes directly. Otherwise, if you simply expose the basic classes to developers, check out the shorter, partial list in the consumer upgrade guide.

+ +

Rendering Changes

+ +

This library no longer differentiates between block renderers and inline renderers - everything now uses “node renderers” which allow us to have a unified approach to rendering! As a result, the following changes were made, which you may need to change in your custom extensions:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Old Method/Interface (1.x)New Method/Interface (2.0)
BlockRendererInterfaceNodeRendererInterface
InlineRendererInterfaceNodeRendererInterface
EnvironmentInterface::getBlockRenderersForClass()EnvironmentInterface::getRenderersForClass()
EnvironmentInterface::getInlineRenderersForClass()EnvironmentInterface::getRenderersForClass()
ConfigurableEnvironmentInterface::addBlockRenderer()ConfigurableEnvironmentInterface::addRenderer()
ConfigurableEnvironmentInterface::addInlineRenderer()ConfigurableEnvironmentInterface::addRenderer()
ElementRendererInterface::renderBlock()ChildNodeRendererInterface::renderNodes()
ElementRendererInterface::renderBlocks()ChildNodeRendererInterface::renderNodes()
ElementRendererInterface::renderInline()ChildNodeRendererInterface::renderNodes()
ElementRendererInterface::renderInlines()ChildNodeRendererInterface::renderNodes()
HtmlRenderer::renderBlock($document)HtmlRenderer::renderDocument()
+ +

Renderers now implement the unified NodeRendererInterface which has a similar (but slightly different) signature from +the old BlockRendererInterface and InlineRendererInterface interfaces:

+ +
/**
+ * @param Node                       $node
+ * @param ChildNodeRendererInterface $childRenderer
+ *
+ * @return HtmlElement|string|null
+ */
+public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The element being rendered is still passed in the first argument, and the object that helps you render children is still +passed in the second argument. Note that blocks are no longer told whether they’re being rendered in a tight list - if you +need to know about this, traverse up the $node AST yourself and check any ListBlock ancestor for tightness.

+ +

Removed Classes

+ +

The following classes have been removed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Class name in 1.xReplacement / Notes
AbstractStringContainerBlockUse extends AbstractBlock implements StringContainerInterface instead. Note the new method names.
ContextUse MarkdownParserState instead (has different methods but serves a similar purpose)
ContextInterfaceUse MarkdownParserStateInterface instead (has different methods but serves a similar purpose)
ConverterUse MarkdownConverter instead.
ConverterInterfaceUse MarkdownConverterInterface. This interface has the same methods so it should be a drop-in replacement.
UnmatchedBlockCloserNo longer needed 2.x
+ +

Renamed constants

+ +

The following constants have been moved/renamed:

+ + + + + + + + + + + + + + + + + + + + + + +
Old Name/Location (1.x)New Name/Location (2.0)
EnvironmentInterface::HTML_INPUT_ALLOWHtmlFilter::ALLOW
EnvironmentInterface::HTML_INPUT_ESCAPEHtmlFilter::ESCAPE
EnvironmentInterface::HTML_INPUT_STRIPHtmlFilter::STRIP
+ +

Renamed Methods

+ +

The following methods have been renamed:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ClassOld Name (1.x)New Name (2.0)
Environment / ConfigurableEnvironmentInterfaceaddBlockParser()addBlockStartParser()
ReferenceMap / ReferenceMapInterfaceaddReference()add()
ReferenceMap / ReferenceMapInterfacegetReference()get()
ReferenceMap / ReferenceMapInterfacelistReferences()getIterator()
+ +

Configuration Method Changes

+ +

Calling EnvironmentInterface::getConfig() without any parameters is no longer supported.

+ +

Calling ConfigurableEnvironmentInterface::mergeConfig() without any parameters is no longer supported.

+ +

The ConfigurableEnvironmentInterface::setConfig() method has been removed. Use getConfig() instead.

+ +

bin/commonmark command

+ +

This command was buggy to test and was relatively unpopular, so it has been removed. If you need this type of functionality, consider writing your own script with a Converter/Environment configured exactly how you want it.

+ +

CommonMarkConverter::VERSION constant

+ +

This previously-deprecated constant was removed in 2.0 Use \Composer\InstalledVersions provided by composer-runtime-api instead.

+ +

HeadingPermalinkRenderer::DEFAULT_INNER_CONTENTS constant

+ +

This previously-deprecated constant was removed in 2.0. Use HeadingPermalinkRenderer::DEFAULT_SYMBOL instead.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.0/xml/index.html b/2.0/xml/index.html new file mode 100644 index 0000000000..b4227b77fe --- /dev/null +++ b/2.0/xml/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + XML Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.0. Please consider upgrading your code to the latest stable version

+ + +

XML Rendering

+ +

Version 2.0 introduced the ability to render Markdown Document objects in XML. This is particularly useful for debugging custom extensions.

+ +

To convert Markdown to XML, you would instantiate an Environment, parse the Markdown into an AST, and render it using the new XmlRenderer:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Xml\XmlRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$renderer = new XmlRenderer($environment);
+
+$document = $parser->parse('# **Hello** World!');
+
+echo $renderer->renderDocument($document);
+
+ +

This will display XML output like this:

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<document xmlns="http://commonmark.org/xml/1.0">
+    <heading level="1">
+        <strong>
+            <text>Hello</text>
+        </strong>
+        <text> World!</text>
+    </heading>
+</document>
+
+ +

Return Value

+ +

Like with CommonMarkConverter::convertToHtml(), the renderDocument() actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final XML output.

+ +

Customizing the XML Output

+ +

See the rendering documentation for information on customizing the XML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/basic-usage/index.html b/2.1/basic-usage/index.html new file mode 100644 index 0000000000..250f22797f --- /dev/null +++ b/2.1/basic-usage/index.html @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Using Extensions

+ +

The CommonMarkConverter and GithubFlavoredMarkdownConverter shown above automatically configure the environment for you, but if you want to use additional extensions you’ll need to avoid those classes and use the generic MarkdownConverter class instead to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

Configuration

+ +

If you’re using the CommonMarkConverter or GithubFlavoredMarkdownConverter class you can pass configuration options directly into their constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

See the configuration section for more information on the available configuration options.

+ +

Supported Character Encodings

+ +

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.

+ +

Return Value

+ +

The convertToHtml() method actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final HTML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/changelog/index.html b/2.1/changelog/index.html new file mode 100644 index 0000000000..feaf30ab50 --- /dev/null +++ b/2.1/changelog/index.html @@ -0,0 +1,829 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 2.x releases are shown below. See the full list of releases for the complete changelog.

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

2.4.4 - 2024-07-22

+ +

Fixed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

+ +

2.4.3 - 2024-07-22

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.2…2.4.3

+ +

2.4.2 - 2024-02-02

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.1…2.4.2

+ +

2.4.1 - 2023-08-30

+ +

Fixed

+ + + +

2.4.0 - 2023-03-24

+ +

See the upgrading guide for more information about the exception-related changes

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

2.3.9 - 2023-02-15

+ +

Fixed

+ + + +

2.3.8 - 2022-12-10

+ +

Fixed

+ + + +

2.3.7 - 2022-11-17

+ +

Fixed

+ + + +

2.3.6 - 2022-10-30

+ +

Fixed

+ + + +

2.3.5 - 2022-07-29

+ +

Fixed

+ + + +

2.3.4 - 2022-07-17

+ +

Changed

+ + + +

Fixed

+ + + +

2.3.3 - 2022-06-07

+ +

Fixed

+ + + +

2.3.2 - 2022-06-03

+ +

Fixed

+ + + +

2.2.5 - 2022-06-03

+ +

Fixed

+ + + +

2.3.1 - 2022-05-14

+ +

Fixed

+ + + +

2.2.4 - 2022-05-14

+ +

Fixed

+ + + +

2.3.0 - 2022-04-07

+ +

Added

+ + + +

Deprecated

+ + + +

2.2.3 - 2022-02-26

+ +

Fixed

+ + + +

2.1.3 - 2022-02-26

+ +

Fixed

+ + + +

2.2.2 - 2022-02-13

+ +

Fixed

+ + + +

2.1.2 - 2022-02-13

+ +

Fixed

+ + + +

2.2.1 - 2022-01-25

+ +

Fixed

+ + + +

Removed

+ + + +

2.2.0 - 2022-01-22

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

2.1.1 - 2022-01-02

+ +

Added

+ + + +

2.1.0 - 2021-12-05

+ +

Added

+ + + +

Fixed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/configuration/index.html b/2.1/configuration/index.html new file mode 100644 index 0000000000..755bd74ea3 --- /dev/null +++ b/2.1/configuration/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the Environment or converter classes when creating them:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+    'slug_normalizer' => [
+        'max_length' => 255,
+    ],
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of the core configuration options available:

+ + + +

Additional configuration options are available for most of the available extensions - refer to their individual documentation for more details. For example, the CommonMark core extension offers these additional options:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/abstract-syntax-tree/index.html b/2.1/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..de78f7619e --- /dev/null +++ b/2.1/customization/abstract-syntax-tree/index.html @@ -0,0 +1,702 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Visualization

+ +

Even with an interactive debugger it can be tricky to view an entire tree at once. Consider using the XmlRenderer to provide a simple text-based representation of the AST for debugging purposes.

+ +

Node Traversal

+ +

There are four different ways to traverse/iterate the Nodes within the AST:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodProsCons
Manual TraversalBest way to access/check direct relatives of nodesNot useful for iteration
Iterating the TreeFast and efficientPossible unexpected behavior when adding/removing sibling nodes while iterating
Walking the TreeFull control over iterationUp to twice as slow as iteration; adding/removing nodes while iterating can lead to weird behaviors
Querying NodesEasier to write and understand; no weird behaviorsNot memory efficient
+ +

Each is described in more detail below

+ +

Manual Traversal

+ +

The following methods can be used to manually traverse from one Node to any of its direct relatives:

+ + + +

This is best suited for situations when you need to know information about those relatives.

+ +

Iterating the Tree

+ +

If you’d like to iterate through all the nodes, use the iterator() method to obtain an iterator that will loop through each node in the tree (using pre-order traversal):

+ +
foreach ($document->iterator() as $node) {
+    echo 'Current node: ' . get_class($node) . "\n";
+}
+
+ +

Given an AST like this (XML representation):

+ +
<document>
+  <heading level="1">
+    <text>Hello World!</text>
+  </heading>
+  <paragraph>
+    <text>This is an example of </text>
+    <strong>
+      <text>CommonMark</text>
+    </strong>
+    <text>.</text>
+  </paragraph>
+</document>
+
+ +

The code above will output:

+ +
Current node: League\CommonMark\Node\Block\Document
+Current node: League\CommonMark\Extension\CommonMark\Node\Block\Heading
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Block\Paragraph
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Extension\CommonMark\Node\Inline\Strong
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Inline\Text
+
+ +

This iterator doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes. It’s also very CPU and memory-efficient.

+ +

Be careful when modifying nodes while iterating the tree as some of those changes may affect the current iteration process, especially for sibling nodes that come after the current one. For example, if you remove the current node’s next() sibling, the next loop of that iteration will still include the removed sibling even though it was successfully removed from the AST. Similarly, any new siblings that are added won’t be visited on the next loop.

+ +

Walking the Tree

+ +

If you’d like to walk through all the nodes, visiting each one as you enter and leave it, use the walker() method to obtain an instance of NodeWalker. This also uses pre-order traversal but emitting NodeWalkerEvents along the way:

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'Now ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

Using the same example AST in the previous section, this code will output:

+ +
Now entering a League\CommonMark\Node\Block\Document node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Block\Paragraph node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Node\Block\Paragraph node
+Now leaving a League\CommonMark\Node\Block\Document node
+
+ +

This approach offers many of the same benefits as the simple iteration shown in the previous section such as memory efficiency and no recursion. The key differences come from how you enter and leave nodes:

+ +
    +
  1. Iteration can potentially take twice as long - not ideal for performance
  2. +
  3. Provides you with more control over exactly when an action is taken on a node which is sometimes needed for certain AST manipulations
  4. +
  5. Also provides a resumeAt() method to override where it should iterate next
  6. +
+ +

But like with the iterator, be careful when adding/removing nodes while walking the tree, as there are even more subtle cases where the walker could even lose track of where it was, which may result in some nodes being visited multiple times or not at all.

+ +

Querying Nodes

+ +

If you’re trying to locate certain nodes to perform actions on them, querying the nodes from the AST might be easier to implement. This can be done with the Query class:

+ +
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Query;
+
+// Find all paragraphs and blockquotes that contain links
+$matchingNodes = (new Query())
+    ->where(Query::type(Paragraph::class))
+    ->orWhere(Query::type(BlockQuote::class))
+    ->andWhere(Query::hasChild(Query::type(Link::class)))
+    ->findAll($document);
+
+foreach ($matchingNodes as $node) {
+    // TODO: Do something with them
+}
+
+ +

Each condition passed into where(), orWhere(), or andWhere() must be a callable “filter” that accepts a Node and returns true or false. We provide several methods that can help create these filters for you:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Query::type(string $class)Creates a filter that matches nodes with the given class name
Query::hasChild()Creates a filter that matches nodes which contain at least one child
Query::hasChild(callable $condition)Creates a filter that matches nodes which contain at least one child that matches the inner $condition
Query::hasParent()Creates a filter that matches nodes which have a parent
Query::hasParent(callable $condition)Creates a filter that matches nodes which have a parent that matches the inner $condition
+ +

You can of course create your own custom filters/conditions using an anonymous function or by implementing ExpressionInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Node\Query;
+use League\CommonMark\Node\Query\ExpressionInterface;
+
+class ChildCountGreaterThan implements ExpressionInterface
+{
+    private $count;
+
+    public function __construct(int $count)
+    {
+        $this->count = $count;
+    }
+
+    public function __invoke(Node $node) : bool{
+        return count($node->children()) > $this->count;
+    }
+}
+
+$query = (new Query())
+    ->where(function (Node $node): bool { return $node->data->has('attributes/class'); })
+    ->andWhere(new ChildCountGreaterThan(3));
+
+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ +

Data Storage

+ +

Each Node has a property called data which is a Data (array-like) object. This can be used to store any arbitrary data you’d like on the node:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text1 = new Text('Hello, world!');
+$text1->data->set('language', 'English');
+$text1->data->set('is_good_translation', true);
+
+$text2 = new Text('Bonjour monde!');
+$text2->data->set('language', 'French');
+$text2->data->set('is_good_translation', false);
+
+foreach ([$text1, $text2] as $text) {
+    if ($text->data->get('is_good_translation')) {
+        sprintf('In %s we would say: "%s"', $text->data->get('language'), $text->getLiteral());
+    } else {
+        sprintf('I think they would say "%s" in %s, but I\'m not sure.', $text->getLiteral(), $text->data->get('language'));
+    }
+}
+
+ +

You can also access deeply-nested paths using / or . as delimiters:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text = new Text('Hello, world!');
+$text->data->set('info', ['language' => 'English', 'is_good_translation' => true]);
+
+var_dump($text->data->get('info/language'));
+var_dump($text->data->get('info.is_good_translation'));
+
+$text->data->set('info/is_example', true);
+
+ +

HTML Attributes

+ +

The data property comes pre-instantiated with a single data element called attributes which is used to store any HTML attributes that need to be rendered. For example:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+$link = new Link('https://twitter.com/colinodell', '@colinodell');
+$link->data->append('attributes/class', 'social-link');
+$link->data->append('attributes/class', 'twitter');
+$link->data->set('attributes/target', '_blank');
+$link->data->set('attributes/rel', 'noopener');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/block-parsing/index.html b/2.1/customization/block-parsing/index.html new file mode 100644 index 0000000000..004759b26b --- /dev/null +++ b/2.1/customization/block-parsing/index.html @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

At a high level, block parsing is a two-step process:

+ +
    +
  1. Using a BlockStartParserInterface to identify if/where a block start exists on the given line
  2. +
  3. Using a BlockContinueParserInterface to perform additional processing of the identified block
  4. +
+ +

So to implement a custom block parser you will actually need to implement both of these classes.

+ +

BlockStartParserInterface

+ +

Instances of this interface have a single tryStart() method:

+ +
/**
+ * Check whether we should handle the block at the current position
+ *
+ * @param Cursor                       $cursor
+ * @param MarkdownParserStateInterface $parserState
+ *
+ * @return BlockStart|null
+ */
+public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart;
+
+ +

Given a Cursor at the current position, plus some extra information about the state of the parser, this method is responsible for determining whether a particular type of block seems to exist at the given position. You don’t actually parse the block here - that’s the job of a BlockContinueParserInterface. Your only job here is to return whether or not a particular type of block does exist here, and if so which block parser should parse it.

+ +

If you find that you cannot parse the given block, you should return BlockStart::none(); from this function.

+ +

However, if the Markdown at the current position does indeed seem to be the type of block you’re looking for, you should return a BlockStart instance using the following static constructor pattern:

+ +
use League\CommonMark\Parser\Block\BlockStart;
+
+return BlockStart::of(new MyCustomParser())->at($cursor);
+
+ +

Unlike in 1.x, the Cursor state is no longer shared between parsers. You must therefore explicitly provide the BlockStart object with a copy of your cursor at the correct, post-parsing position.

+ +

NOTE: If your custom block starts with a letter character you’ll need to add your parser to the environment with a priority of 250 or higher. This is due to a performance optimization where such lines are usually skipped.

+ +

BlockContinueParserInterface

+ +

The previous interface only helps the engine identify where a block starts. Additional information about the block, as well as the ability to parse additional lines of input, is all handled by the BlockContinueParserInterface.

+ +

This interface has several methods, so it’s usually easier to extend from AbstractBlockContinueParser instead, which sets most of the methods to use typical defaults you can override as needed.

+ +

getBlock()

+ +
public function getBlock(): AbstractBlock;
+
+ +

Each instance of a BlockContinueParserInterface is associated with a new block that is being parsed. This method here returns that block.

+ +

isContainer()

+ +
public function isContainer(): bool;
+
+ +

This method returns whether or not the block is a “container” capable of containing other blocks as children.

+ +

canContain()

+ +
public function canContain(AbstractBlock $childBlock): bool;
+
+ +

This method returns whether the current block being parsed can contain the given child block.

+ +

canHaveLazyContinuationLines()

+ +
public function canHaveLazyContinuationLines(): bool;
+
+ +

This method returns whether or not this parser should also receive subsequent lines of Markdown input. This is primarily used when a block can span multiple lines, like code blocks do.

+ +

addLine()

+ +
public function addLine(string $line): void;
+
+ +

If canHaveLazyContinuationLines() returned true, this method will be called with the additional lines of content.

+ +

tryContinue()

+ +
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue;
+
+ +

This method allows you to try and parse an additional line of Markdown.

+ +

closeBlock()

+ +
public function closeBlock(): void;
+
+ +

This method is called when the block is done being parsed. Any final adjustments to the block should be made at this time.

+ +

parseInlines()

+ +
public function parseInlines(InlineParserEngineInterface $inlineParser): void;
+
+ +

This method is called when the engine is ready to parse any inline child elements.

+ +

Note: For performance reasons, this method is not part of BlockContinueParserInterface. If your block may contain inlines, you should make sure that your “continue parser” also implements BlockContinueParserWithInlinesInterface.

+ +

Tips

+ +

Here are some additional tips to consider when writing your own custom parsers:

+ +

Combining both into one file

+ +

Although parsing requires two classes, you can use the anonymous class feature of PHP to combine both into a single file! Here’s an example:

+ +
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+
+final class MyCustomBlockParser extends AbstractBlockContinueParser
+{
+    // TODO: implement your continuation parsing methods here
+
+    public static function createBlockStartParser(): BlockStartParserInterface
+    {
+        return new class implements BlockStartParserInterface
+        {
+            // TODO: implement the tryStart() method here
+        };
+    }
+}
+
+
+ +

Performance

+ +

The BlockStartParserInterface::tryStart() and BlockContinueParserInterface::tryContinue() methods may be called hundreds or thousands of times during execution. For best performance, have your methods return as early as possible, and make sure your code is highly optimized.

+ +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

If your block contains literal strings/text within the block (and not as part of a child block), you should have your custom block type also implement StringContainerInterface.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/configuration/index.html b/2.1/customization/configuration/index.html new file mode 100644 index 0000000000..e298f88bb3 --- /dev/null +++ b/2.1/customization/configuration/index.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Configuration Schemas and Values

+ +

Version 2.0 introduced a new robust system for defining configuration schemas and accessing them within custom extensions.

+ +

Configuration Schemas

+ +

Unlike in 1.x, all configuration options must have a defined schema. This defines which options are available, what types of values they accept, whether any are required, and any default values you wish to define if the user doesn’t provide any.

+ +

These custom options can be defined from within your custom extension by implementing the ConfigurableExtensionInterface:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+use Nette\Schema\Expect;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        $builder->addSchema('my_extension', Expect::structure([
+            'enable_some_feature' => Expect::bool()->default(true),
+            'html_class' => Expect::string()->default('my-custom-extension'),
+            'align' => Expect::anyOf('left', 'center', 'right')->default('left'),
+            'favorite_number' => Expect::int()->min(1)->max(100)->default(42),
+        ]));
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        // TODO: Implement register() method
+    }
+}
+
+ +

See the league/config documentation for more examples of how to define custom configuration schemas.

+ +

Note that you only need to implement ConfigurableExtensionInterface if you plan to define new configuration options - you don’t need this if you’re only reading existing options.

+ +

Reading Configuration Values

+ +

Okay, so your extension has defined the different options that are available, but now you want to start using them within your custom extension. There are a few ways you can access the values:

+ +

During Extension Registration

+ +

Perhaps your extension needs to decide whether/how to register certain parsers/renderers/etc based on the user-provided configuration values - in that case, you can read the value from the $environment - for example:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        // (see code example above)
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        if ($environment->getConfiguration()->get('my_extension/enable_some_feature')) {
+            $environment->addBlockStartParser(new MyCustomParser());
+            $environment->addRenderer(MyCustomBlockType::class, new MyCustomRenderer());
+        }
+    }
+}
+
+ +

Within Parsers/Renderers/Listeners

+ +

Perhaps you want to reference those configuration values from within a custom parser, renderer, event listener, or something else. This can easily by done by having that class also implement ConfigurationAwareInterface. This interface signals to the Environment that your class needs a copy of the final configuration so it can read it later:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+
+final class MyCustomRenderer implements NodeRendererInterface, ConfigurationAwareInterface
+{
+    /**
+     * @var ConfigurationInterface
+     */
+    private $config;
+
+    public function setConfiguration(ConfigurationInterface $configuration): void
+    {
+        $this->config = $configuration;
+    }
+
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return 'My favorite number is ' . $this->config->get('my_extension/favorite_number');
+    }
+}
+
+ +

You can access any configuration value from here, not just the ones you might have defined yourself.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/cursor/index.html b/2.1/customization/cursor/index.html new file mode 100644 index 0000000000..86b8d73d95 --- /dev/null +++ b/2.1/customization/cursor/index.html @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Parser\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter(int $index)Returns the character at the given absolute position
getCurrentCharacter()Returns the character at the current position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/delimiter-processing/index.html b/2.1/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..b0f338693f --- /dev/null +++ b/2.1/customization/delimiter-processing/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis;
+
+// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
use League\CommonMark\Delimiter\Delimiter;
+use League\CommonMark\Node\Inline\Text;
+
+$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/environment/index.html b/2.1/customization/environment/index.html new file mode 100644 index 0000000000..9dd38456ae --- /dev/null +++ b/2.1/customization/environment/index.html @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all extensions, parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

An empty Environment can be obtained like this:

+ +
use League\CommonMark\Environment\Environment;
+
+$config = [];
+$environment = new Environment($config);
+
+ +

You can customize the Environment using any of the methods below (from the EnvironmentBuilderInterface interface).

+ +

Once your Environment is configured with whatever configuration and extensions you want, you can instantiate a MarkdownConverter and start converting MD to HTML:

+ +
use League\CommonMark\MarkdownConverter;
+
+// Using $environment from the previous code sample
+$converter = new MarkdownConverter($environment);
+
+echo $converter->convertToHtml('# Hello World!');
+
+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. For example, if you want core CommonMark functionality plus footnote support:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+$config = [];
+$environment = new Environment($config);
+
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new FootnoteExtension());
+
+ +

addBlockStartParser()

+ +
public function addBlockStartParser(BlockStartParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockStartParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addRenderer()

+ +
public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0);
+
+ +

Registers a NodeRendererInterface to handle a specific type of AST node ($nodeClass) with the given priority (a higher number will be executed earlier).

+ +

See Rendering for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/event-dispatcher/index.html b/2.1/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..e875ac6f4e --- /dev/null +++ b/2.1/customization/event-dispatcher/index.html @@ -0,0 +1,574 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic, PSR-14-compliant event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code.

+ +

Event Class

+ +

Any PSR-14 compliant event can be used, though we also provide an AbstractEvent class you can use to easily create your own events:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - the event object to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

League\CommonMark\Event\DocumentPreRenderEvent

+ +

This event is dispatched by the renderer just before rendering begins. Like with DocumentParsedEvent, this offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering, but with the added knowledge of which format is being rendered to (e.g. html).

+ +

League\CommonMark\Event\DocumentRenderedEvent

+ +

This event is dispatched once the rendering step has been completed, just before the output is returned. The final output can be adjusted at this point or additional metadata can be attached to the return object.

+ +

Bring Your Own PSR-14 Event Dispatcher

+ +

Although this library provides PSR-14 compliant event dispatching out-of-the-box, you may want to use your own PSR-14 event dispatcher instead. This is possible as long as that third-party library both:

+ +
    +
  1. Implements the PSR-14 EventDispatcherInterface; and,
  2. +
  3. Allows you to register additional ListenerProviderInterface instances with that dispatcher library
  4. +
+ +

Not all libraries support this so please check carefully! Assuming yours does, delegating all the event behavior to that library can be done with two steps:

+ +

First, call the setEventDispatcher() method on the Environment to register that other implementation. With that done, any calls to Environment::dispatch() will be passed through to that other dispatcher. But we still need to let that dispatcher know about the events registered by CommonMark extensions, otherwise nothing will happen when events are dispatched.

+ +

Because the Environment implements PSR-14’s ListenerProviderInterface you’ll also need to pass the configured Environment object to your event dispatcher so that it becomes aware of those available events.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event): void
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data->append('attributes/class', 'external-link');
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfiguration()->get('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = new Environment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convertToHtml($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/extensions/index.html b/2.1/customization/extensions/index.html new file mode 100644 index 0000000000..c757afaf66 --- /dev/null +++ b/2.1/customization/extensions/index.html @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a EnvironmentBuilderInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new EmojiExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/inline-parsing/index.html b/2.1/customization/inline-parsing/index.html new file mode 100644 index 0000000000..a5742757f3 --- /dev/null +++ b/2.1/customization/inline-parsing/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getMatchDefinition()

+ +

This method should return an instance of InlineParserMatch which defines the text the parser is looking for. Examples of this might be something like:

+ +
use League\CommonMark\Parser\Inline\InlineParserMatch;
+
+InlineParserMatch::string('@');                  // Match any '@' characters found in the text
+InlineParserMatch::string('foo');                // Match the text 'foo' (case insensitive)
+
+InlineParserMatch::oneOf('@', '!');              // Match either character
+InlineParserMatch::oneOf('http://', 'https://'); // Match either string
+
+InlineParserMatch::regex('\d+');                 // Match the regular expression (omit the regex delimiters and any flags)
+
+ +

Once a match is found, the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has found at a matching string in the current line; and,
  2. +
  3. No other inline parsers with a higher priority have successfully parsed the text at this point in the line
  4. +
+ +

Parameters

+ + + +
InlineParserContext
+ +

This class has several useful methods:

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the text at the current position for any reason. Other parsers will then have a chance to try parsing that text. If all registered parsers return false, the text will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed/matched text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::regex('@([A-Za-z0-9_]{1,15}(?!\w))');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+
+        // This seems to be a valid match
+        // Advance the cursor to the end of the match
+        $cursor->advanceBy($inlineContext->getFullMatchLength());
+
+        // Grab the Twitter handle
+        [$handle] = $inlineContext->getSubMatches();
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+// And here's how to hook it up:
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::oneOf(':)', ':(');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($inlineContext->getFullMatch() === ':)') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($inlineContext->getFullMatch() === ':(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/overview/index.html b/2.1/customization/overview/index.html new file mode 100644 index 0000000000..cc2fb239da --- /dev/null +++ b/2.1/customization/overview/index.html @@ -0,0 +1,479 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders/configuration you need
  2. +
  3. Instantiate a MarkdownParser and HtmlRenderer using that Environment
  4. +
  5. Use the MarkdownParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  6. +
  7. Use the HtmlRenderer to convert the AST Document into HTML
  8. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+$environment = new Environment([
+    'html_input' => 'strip',
+]);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderDocument($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renderers convert the parsed blocks/inlines from the AST representation into HTML. When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/rendering/index.html b/2.1/customization/rendering/index.html new file mode 100644 index 0000000000..8357c7652a --- /dev/null +++ b/2.1/customization/rendering/index.html @@ -0,0 +1,541 @@ + + + + + + + + + + + + + + + + + Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Custom Rendering

+ +

Renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement NodeRendererInterface and its render() method. Note that in v2.0, both +block renderers and inline renderers share the same interface and method:

+ +

render()

+ +
public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The HtmlRenderer will call this method during the rendering process whenever a supported element is encountered.

+ +

If your renderer can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the node and its contents, including any children. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\Util\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Renderers

+ +

When registering your renderer, you must tell the Environment which node element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// First param - the node class type that should use our renderer
+// Second param - instance of the renderer
+$environment->addRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple types:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak;
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements NodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(ThematicBreak::class, new TextDividerRenderer());
+
+ +

Note that thematic breaks should not contain children, which is why the $childRenderer is unused in this example. Otherwise we’d have to call code like this and return the result as part of the rendered HTML we’re generating here: $innerHtml = $childRenderer->renderNodes($node->children());

+ +

Tips

+ + + +

XML Rendering

+ +

The XML renderer will automatically attempt to convert any AST nodes to XML by inspecting the name of the block/inline node and its attributes. You can instead control the XML element name and attributes by making your renderer implement XmlNodeRendererInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+
+class TextDividerRenderer implements NodeRendererInterface, XmlNodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+
+    public function getXmlTagName(Node $node): string
+    {
+        return 'text_divider';
+    }
+
+    public function getXmlAttributes(Node $node): array
+    {
+        return ['character' => '='];
+    }
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/customization/slug-normalizer/index.html b/2.1/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..9e309377e2 --- /dev/null +++ b/2.1/customization/slug-normalizer/index.html @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + Slug Normalizer - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Slug Normalizer

+ +

“Slugs” are strings used within href, name, and id HTML attributes to identify particular elements within a document.

+ +

Some extensions (like the HeadingPermalinkExtension) need the ability to convert user-provided text into these URL-safe slugs while also ensuring that these are unique throughout the generated HTML. The Environment provides a pre-built normalizer you can use for this purpose.

+ +

Usage

+ +

You can obtain a reference to the built-in slug normalizer by calling $environment->getSlugNormalizer();

+ +

To use this within your extension, have your parser/renderer/whatever implement EnvironmentAwareInterface and then implement the corresponding setEnvironment method like this:

+ +

+use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Environment\EnvironmentAwareInterface;
+
+class MyCustomParserOrRenderer implements EnvironmentAwareInterface
+{
+    private $slugNormalizer;
+
+    public function setEnvironment(EnvironmentInterface $environment): void
+    {
+        $this->slugNormalizer = $environment->getSlugNormalizer();
+    }
+}
+
+ +

You can then call $this->slugNormalizer->normalize($text) as needed.

+ +

Configuration

+ +

The slug_normalizer configuration section allows you to adjust the following options:

+ +

instance

+ +

You can change the string that is used as the “slug” by setting the instance option to any class that implements TextNormalizerInterface. +We provide a simple SlugNormalizer by default, but you may want to plug in a different library or create your own normalizer instead.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

max_length

+ +

This can be configured to limit the length of that slug to prevent overly-long values. By default, that limit is 255 characters. You may set this to any positive integer, or 0 for no limit.

+ +

(Note that generated slugs might be slightly longer than this “limit” if the unique option is enabled and the slug generator detects a duplicate slug and needs to add a suffix to make it unique.)

+ +

unique

+ +

This options controls whether slugs should be unique. Possible values include:

+ + + +

You might have a use case where you’re converting several different Markdown documents on the same page and so you’d like to ensure that none of those documents use conflicting slugs. In that case, you should set the scope option to 'environment' to ensure that a single instance of a MarkdownConverter (which uses a single Environment) will never produce the same slug twice during its lifetime (which usually lasts the entire duration of a single HTTP request).

+ +

If you need complete control over how unique slugs are generated, make your 'instance' implement UniqueSlugNormalizerInterface; otherwise, we’ll simply append incremental numbers to slugs to ensure they are unique.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/attributes/index.html b/2.1/extensions/attributes/index.html new file mode 100644 index 0000000000..1b048dbe75 --- /dev/null +++ b/2.1/extensions/attributes/index.html @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+ +

This results in the following output:

+ +
<blockquote title="Blockquote title">
+<p>A nice blockquote</p>
+</blockquote>
+
+ +

CSS-selector-style declarations can be used to set the id and class attributes:

+ +
{#id .class}
+## Header
+
+ +

Output:

+ +
<h2 class="class" id="id">Header</h2>
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Output:

+ +
<p>This is <em style="color: red">red</em>.</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/autolinks/index.html b/2.1/extensions/autolinks/index.html new file mode 100644 index 0000000000..af37555bd5 --- /dev/null +++ b/2.1/extensions/autolinks/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a Mention Parser outside of this extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/commonmark/index.html b/2.1/extensions/commonmark/index.html new file mode 100644 index 0000000000..92397e4d92 --- /dev/null +++ b/2.1/extensions/commonmark/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically installed for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new Environment with the core extension
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/default-attributes/index.html b/2.1/extensions/default-attributes/index.html new file mode 100644 index 0000000000..63d22e6be9 --- /dev/null +++ b/2.1/extensions/default-attributes/index.html @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + Default Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Default Attributes

+ +

The DefaultAttributesExtension allows you to apply default HTML classes and other attributes using configuration options.

+ +

It works by applying the attributes to the nodes during the DocumentParsedEvent event - right after the nodes are parsed but before they are rendered. +(As a result, it’s possible that renderers may add other attributes - the goal of this extension is only to provide custom defaults.)

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DefaultAttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Node\Block\Paragraph;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'default_attributes' => [
+        Heading::class => [
+            'class' => static function (Heading $node) {
+                if ($node->getLevel() === 1) {
+                    return 'title-main';
+                } else {
+                    return null;
+                }
+            },
+        ],
+        Table::class => [
+            'class' => 'table',
+        ],
+        Paragraph::class => [
+            'class' => ['text-center', 'font-comic-sans'],
+        ],
+        Link::class => [
+            'class' => 'btn btn-link',
+            'target' => '_blank',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new DefaultAttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a default_attributes array. Each key in the array should be a FQCN for the node class you wish to apply the default attribute to, and the values should be a map of attribute names to attribute values.

+ +

Attribute values may be any of the following types:

+ + + +

Examples

+ +

Here’s an example that will apply Bootstrap 4 classes and attributes:

+ +
$config = [
+    'default_attributes' => [
+        Table::class => [
+            'class' => ['table', 'table-responsive'],
+        ],
+        BlockQuote::class => [
+            'class' => 'blockquote',
+        ],
+    ],
+];
+
+ +

Here’s a more complex example that uses a callable to add a class only if the paragraph immediately follows an <h1> heading:

+ +
$config = [
+    'default_attributes' => [
+        Paragraph::class => [
+            'class' => static function (Paragraph $paragraph) {
+                if ($paragraph->previous() instanceof Heading && $paragraph->previous()->getLevel() === 1) {
+                    return 'lead';
+                }
+
+                return null;
+            },
+        ],
+    ],
+];
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/description-lists/index.html b/2.1/extensions/description-lists/index.html new file mode 100644 index 0000000000..7b37d33516 --- /dev/null +++ b/2.1/extensions/description-lists/index.html @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + + Description List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Description List Extension

+ +

The DescriptionListExtension adds Markdown Extra-style description lists to facilitate the creation of <dl>, <dt>, and <dd> HTML using Markdown.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DescriptionListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\DescriptionList\DescriptionListExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DescriptionListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Some markdown goes here');
+
+ +

Syntax

+ +

The syntax is based directly on the rules and logic implemented by the Markdown Extra library. Here are some examples of sample Markdown input and HTML output demonstrating the syntax:

+ +
Apple
+:   Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.
+:   An American computer company.
+
+Orange
+:   The fruit of an evergreen tree of the genus Citrus.
+
+ +
<dl>
+    <dt>Apple</dt>
+    <dd>Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.</dd>
+    <dd>An American computer company.</dd>
+
+    <dt>Orange</dt>
+    <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+
+ +

See the Markdown Extra documentation or our own spec for additional examples.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/disallowed-raw-html/index.html b/2.1/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..c2f227f50c --- /dev/null +++ b/2.1/extensions/disallowed-raw-html/index.html @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically escapes certain HTML tags when rendering raw HTML, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Customize the extension's configuration if needed
+// Default values are shown below - you can omit this configuration if you're happy with those defaults
+// and don't want to customize them
+$config = [
+    'disallowed_raw_html' => [
+        'disallowed_tags' => ['title', 'textarea', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'script', 'plaintext'],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I cannot change the page <title>anymore</title>');
+
+ +

Configuration

+ +

This extension can be configured by providing a disallowed_raw_html array with the following nested configuration options. The defaults are shown in the code example above.

+ +

disallowed_tags

+ +

An array containing a list of tags that should be escaped.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/external-links/index.html b/2.1/extensions/external-links/index.html new file mode 100644 index 0000000000..dcd8129248 --- /dev/null +++ b/2.1/extensions/external-links/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class MyCustomLinkRenderer implements NodeRendererInterface
+{
+    /**
+     * @param Node                       $node
+     * @param ChildNodeRendererInterface $childRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        if (!($node instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible node type: ' . \get_class($node));
+        }
+
+        if ($node->data->get('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/footnotes/index.html b/2.1/extensions/footnotes/index.html new file mode 100644 index 0000000000..d539782c9c --- /dev/null +++ b/2.1/extensions/footnotes/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1"></a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'backref_symbol'     => '↩',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

backref_symbol

+ +

This string option sets the symbol used as the contents of the footnote backreference link. It defaults to \League\CommonMark\Extension\Footnote\Renderer\FootnoteBackrefRenderer::DEFAULT_SYMBOL = '↩'.

+ +

If you want to use a custom icon, set this to an empty string '' and take a look at the Adding Icons section below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ +

Adding Icons

+ +

You can use CSS to add a custom icon instead of providing a backref_symbol:

+ +
$config = [
+    'footnote' => [
+        'backref_class' => 'footnote-backref',
+        'backref_symbol' => '',
+    ],
+];
+
+ +

Then target the backref_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.footnote-backref::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/front-matter/index.html b/2.1/extensions/front-matter/index.html new file mode 100644 index 0000000000..64185f5b6c --- /dev/null +++ b/2.1/extensions/front-matter/index.html @@ -0,0 +1,542 @@ + + + + + + + + + + + + + + + + + Front Matter Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Front Matter Extension

+ +

The FrontMatterExtension adds the ability to parse YAML front matter from the Markdown document and include that in the return result.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

You will also need to install symfony/yaml or the YAML extension for PHP to use this extension. For symfony/yaml:

+ +
composer require symfony/yaml
+
+ +

(You can use any version of symfony/yaml 2.3 or higher, though we recommend using 4.0 or higher.)

+ +

Front Matter Syntax

+ +

This extension follows the Jekyll Front Matter syntax. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:

+ +
---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+
+ +

This will produce a front matter array similar to this:

+ +
$parsedFrontMatter = [
+    'layout' => 'post',
+    'title' => 'I Love Markdown',
+    'tags' => [
+        'test',
+        'example',
+    ],
+];
+
+ +

And the HTML output will only contain the one heading:

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

Usage

+ +

Configure your Environment as usual and add the FrontMatterExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FrontMatterExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+// A sample Markdown file with some front matter:
+$markdown = <<<MD
+---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+MD;
+
+$result = $converter->convertToHtml($markdown);
+
+// Grab the front matter:
+if ($result instanceof RenderedContentWithFrontMatter) {
+    $frontMatter = $result->getFrontMatter();
+}
+
+// Output the HTML using any of these:
+echo $result;               // implicit string cast
+// or:
+echo (string) $result;      // explicit string cast
+// or:
+echo $result->getContent();
+
+ +

Parsing Front Matter Only

+ +

You don’t have to parse the entire file (including all the Markdown) if you only want the front matter. You can either instantiate the front matter parser yourself and call it directly, like this:

+ +
use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+// For `symfony/yaml`
+$frontMatterParser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
+// For YAML extension
+$frontMatterParser = new FrontMatterParser(new LibYamlFrontMatterParser());
+$result = $frontMatterParser->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

Or you can use the getFrontMatterParser() method from the extension:

+ +
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+$frontMatterExtension = new FrontMatterExtension();
+$result = $frontMatterExtension->getFrontMatterParser()->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

This latter approach may be more convenient if you have already instantiated a FrontMatterExtension object you’re adding to the Environment somewhere and just want to call that.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/github-flavored-markdown/index.html b/2.1/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..0912578d0d --- /dev/null +++ b/2.1/extensions/github-flavored-markdown/index.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark and GFM parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/heading-permalinks/index.html b/2.1/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..8f957c7851 --- /dev/null +++ b/2.1/extensions/heading-permalinks/index.html @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'content',
+        'fragment_prefix' => 'content',
+        'insert' => 'before',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'aria_hidden' => true,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

fragment_prefix

+ +

This should be a string you want prepended to the URL fragment in the link’s href attribute. This should typically be set to the same value as id_prefix for links to work properly. However, you may not want to expose that same prefix in your URLs - in that case, you can set this to something different (even an empty string) and use JavaScript to “rewrite” them.

+ +

For example, to emulate how GitHub heading permalinks work, set id_prefix to 'user-content', set fragment_prefix to '', and insert some JavaScript into the page like this:

+ +
var scrollToPermalink = function() {
+    var link = document.getElementById('user-content-' + window.location.hash);
+    if (link) {
+        link.scrollIntoView({behavior: 'smooth'});
+    }
+};
+
+window.addEventListener('hashchange', scrollToPermalink);
+if (window.location.hash) {
+    scrollToPermalink();
+}
+
+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

min_heading_level and max_heading_level

+ +

These two settings control which headings should have permalinks added. By default, all 6 levels (1, 2, 3, 4, 5, and 6) will have them. You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

aria_hidden

+ +

This option sets the aria-hidden attribute on the <a> tag. This defaults to aria-hidden="true".

+ +

Setting this option to false would render the <a> tag excluding the aria-hidden entirely.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/inlines-only/index.html b/2.1/extensions/inlines-only/index.html new file mode 100644 index 0000000000..b51e241971 --- /dev/null +++ b/2.1/extensions/inlines-only/index.html @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new, empty environment
+$environment = new Environment($config);
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/mentions/index.html b/2.1/extensions/mentions/index.html new file mode 100644 index 0000000000..096b691ea0 --- /dev/null +++ b/2.1/extensions/mentions/index.html @@ -0,0 +1,666 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting prefix, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the first mention parser to
+        // successfully match and return a properly constructed Mention object (where the URL has been set) will be the
+        // the mention parser that is used. In this example, the GitHub handle would actually match first because
+        // there isn't any real validation to check whether https://www.github.com/colinodell exists. However, in
+        // CMS applications, you could check whether its a local user first, then check Twitter and then GitHub, etc.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Follow me on GitHub: @colinodell');
+// Output:
+// <p>Follow me on GitHub: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regular expression pattern (without opening/closing delimiter or modifiers), or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Inline\Element\AbstractInline;
+
+class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/overview/index.html b/2.1/extensions/overview/index.html new file mode 100644 index 0000000000..4412f8ab55 --- /dev/null +++ b/2.1/extensions/overview/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Default AttributesEasily apply default HTML classes using configuration options to match your site’s styles2.0.0 
Description ListsCreate <dl> description lists using Markdown Extra’s syntax2.0.0 
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
Front MatterParses YAML front matter from your Markdown input2.0.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the extensions you need
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the other extensions you need
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/smart-punctuation/index.html b/2.1/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..f6aeb194d5 --- /dev/null +++ b/2.1/extensions/smart-punctuation/index.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/strikethrough/index.html b/2.1/extensions/strikethrough/index.html new file mode 100644 index 0000000000..a00ade166a --- /dev/null +++ b/2.1/extensions/strikethrough/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/table-of-contents/index.html b/2.1/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..f3a34191ce --- /dev/null +++ b/2.1/extensions/table-of-contents/index.html @@ -0,0 +1,597 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
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;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/tables/index.html b/2.1/extensions/tables/index.html new file mode 100644 index 0000000000..c7d34e3b68 --- /dev/null +++ b/2.1/extensions/tables/index.html @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convertToHtml('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/extensions/task-lists/index.html b/2.1/extensions/task-lists/index.html new file mode 100644 index 0000000000..9c9a1f6673 --- /dev/null +++ b/2.1/extensions/task-lists/index.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convertToHtml($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/index.html b/2.1/index.html new file mode 100644 index 0000000000..2fa029fe3c --- /dev/null +++ b/2.1/index.html @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello, World!')->getContent();
+
+// <h1>Hello, World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/installation/index.html b/2.1/installation/index.html new file mode 100644 index 0000000000..b2a36db4f4 --- /dev/null +++ b/2.1/installation/index.html @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +
composer require "league/commonmark:^2.1"
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^2.1. This is equivalent to >=2.1 <3.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/security/index.html b/2.1/security/index.html new file mode 100644 index 0000000000..43daf6d90d --- /dev/null +++ b/2.1/security/index.html @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convertToHtml('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convertToHtml($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/support/index.html b/2.1/support/index.html new file mode 100644 index 0000000000..457c661fb6 --- /dev/null +++ b/2.1/support/index.html @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/upgrading/index.html b/2.1/upgrading/index.html new file mode 100644 index 0000000000..443c098d5c --- /dev/null +++ b/2.1/upgrading/index.html @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + Upgrading from 2.0 to 2.1 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 2.0 to 2.1

+ +

No changes or deprecations were made that require changes to upgrade to the new version.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.1/xml/index.html b/2.1/xml/index.html new file mode 100644 index 0000000000..86fe2696dd --- /dev/null +++ b/2.1/xml/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + XML Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.1. Please consider upgrading your code to the latest stable version

+ + +

XML Rendering

+ +

Version 2.0 introduced the ability to render Markdown Document objects in XML. This is particularly useful for debugging custom extensions.

+ +

To convert Markdown to XML, you would instantiate an Environment, parse the Markdown into an AST, and render it using the new XmlRenderer:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Xml\XmlRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$renderer = new XmlRenderer($environment);
+
+$document = $parser->parse('# **Hello** World!');
+
+echo $renderer->renderDocument($document);
+
+ +

This will display XML output like this:

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<document xmlns="http://commonmark.org/xml/1.0">
+    <heading level="1">
+        <strong>
+            <text>Hello</text>
+        </strong>
+        <text> World!</text>
+    </heading>
+</document>
+
+ +

Return Value

+ +

Like with CommonMarkConverter::convertToHtml(), the renderDocument() actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final XML output.

+ +

Customizing the XML Output

+ +

See the rendering documentation for information on customizing the XML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/basic-usage/index.html b/2.2/basic-usage/index.html new file mode 100644 index 0000000000..087cf16f56 --- /dev/null +++ b/2.2/basic-usage/index.html @@ -0,0 +1,496 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Using Extensions

+ +

The CommonMarkConverter and GithubFlavoredMarkdownConverter shown above automatically configure the environment for you, but if you want to use additional extensions you’ll need to avoid those classes and use the generic MarkdownConverter class instead to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

Configuration

+ +

If you’re using the CommonMarkConverter or GithubFlavoredMarkdownConverter class you can pass configuration options directly into their constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

See the configuration section for more information on the available configuration options.

+ +

Supported Character Encodings

+ +

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.

+ +

Return Value

+ +

The convert() method actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final HTML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/changelog/index.html b/2.2/changelog/index.html new file mode 100644 index 0000000000..be7687b826 --- /dev/null +++ b/2.2/changelog/index.html @@ -0,0 +1,788 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 2.x releases are shown below. See the full list of releases for the complete changelog.

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

2.4.4 - 2024-07-22

+ +

Fixed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

+ +

2.4.3 - 2024-07-22

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.2…2.4.3

+ +

2.4.2 - 2024-02-02

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.1…2.4.2

+ +

2.4.1 - 2023-08-30

+ +

Fixed

+ + + +

2.4.0 - 2023-03-24

+ +

See the upgrading guide for more information about the exception-related changes

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

2.3.9 - 2023-02-15

+ +

Fixed

+ + + +

2.3.8 - 2022-12-10

+ +

Fixed

+ + + +

2.3.7 - 2022-11-17

+ +

Fixed

+ + + +

2.3.6 - 2022-10-30

+ +

Fixed

+ + + +

2.3.5 - 2022-07-29

+ +

Fixed

+ + + +

2.3.4 - 2022-07-17

+ +

Changed

+ + + +

Fixed

+ + + +

2.3.3 - 2022-06-07

+ +

Fixed

+ + + +

2.3.2 - 2022-06-03

+ +

Fixed

+ + + +

2.2.5 - 2022-06-03

+ +

Fixed

+ + + +

2.3.1 - 2022-05-14

+ +

Fixed

+ + + +

2.2.4 - 2022-05-14

+ +

Fixed

+ + + +

2.3.0 - 2022-04-07

+ +

Added

+ + + +

Deprecated

+ + + +

2.2.3 - 2022-02-26

+ +

Fixed

+ + + +

2.2.2 - 2022-02-13

+ +

Fixed

+ + + +

2.2.1 - 2022-01-25

+ +

Fixed

+ + + +

Removed

+ + + +

2.2.0 - 2022-01-22

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/configuration/index.html b/2.2/configuration/index.html new file mode 100644 index 0000000000..81327a6a45 --- /dev/null +++ b/2.2/configuration/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the Environment or converter classes when creating them:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+    'slug_normalizer' => [
+        'max_length' => 255,
+    ],
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of the core configuration options available:

+ + + +

Additional configuration options are available for most of the available extensions - refer to their individual documentation for more details. For example, the CommonMark core extension offers these additional options:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/abstract-syntax-tree/index.html b/2.2/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..bd3eeaa9ed --- /dev/null +++ b/2.2/customization/abstract-syntax-tree/index.html @@ -0,0 +1,702 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Visualization

+ +

Even with an interactive debugger it can be tricky to view an entire tree at once. Consider using the XmlRenderer to provide a simple text-based representation of the AST for debugging purposes.

+ +

Node Traversal

+ +

There are four different ways to traverse/iterate the Nodes within the AST:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodProsCons
Manual TraversalBest way to access/check direct relatives of nodesNot useful for iteration
Iterating the TreeFast and efficientPossible unexpected behavior when adding/removing sibling nodes while iterating
Walking the TreeFull control over iterationUp to twice as slow as iteration; adding/removing nodes while iterating can lead to weird behaviors
Querying NodesEasier to write and understand; no weird behaviorsNot memory efficient
+ +

Each is described in more detail below

+ +

Manual Traversal

+ +

The following methods can be used to manually traverse from one Node to any of its direct relatives:

+ + + +

This is best suited for situations when you need to know information about those relatives.

+ +

Iterating the Tree

+ +

If you’d like to iterate through all the nodes, use the iterator() method to obtain an iterator that will loop through each node in the tree (using pre-order traversal):

+ +
foreach ($document->iterator() as $node) {
+    echo 'Current node: ' . get_class($node) . "\n";
+}
+
+ +

Given an AST like this (XML representation):

+ +
<document>
+  <heading level="1">
+    <text>Hello World!</text>
+  </heading>
+  <paragraph>
+    <text>This is an example of </text>
+    <strong>
+      <text>CommonMark</text>
+    </strong>
+    <text>.</text>
+  </paragraph>
+</document>
+
+ +

The code above will output:

+ +
Current node: League\CommonMark\Node\Block\Document
+Current node: League\CommonMark\Extension\CommonMark\Node\Block\Heading
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Block\Paragraph
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Extension\CommonMark\Node\Inline\Strong
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Inline\Text
+
+ +

This iterator doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes. It’s also very CPU and memory-efficient.

+ +

Be careful when modifying nodes while iterating the tree as some of those changes may affect the current iteration process, especially for sibling nodes that come after the current one. For example, if you remove the current node’s next() sibling, the next loop of that iteration will still include the removed sibling even though it was successfully removed from the AST. Similarly, any new siblings that are added won’t be visited on the next loop.

+ +

Walking the Tree

+ +

If you’d like to walk through all the nodes, visiting each one as you enter and leave it, use the walker() method to obtain an instance of NodeWalker. This also uses pre-order traversal but emitting NodeWalkerEvents along the way:

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'Now ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

Using the same example AST in the previous section, this code will output:

+ +
Now entering a League\CommonMark\Node\Block\Document node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Block\Paragraph node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Node\Block\Paragraph node
+Now leaving a League\CommonMark\Node\Block\Document node
+
+ +

This approach offers many of the same benefits as the simple iteration shown in the previous section such as memory efficiency and no recursion. The key differences come from how you enter and leave nodes:

+ +
    +
  1. Iteration can potentially take twice as long - not ideal for performance
  2. +
  3. Provides you with more control over exactly when an action is taken on a node which is sometimes needed for certain AST manipulations
  4. +
  5. Also provides a resumeAt() method to override where it should iterate next
  6. +
+ +

But like with the iterator, be careful when adding/removing nodes while walking the tree, as there are even more subtle cases where the walker could even lose track of where it was, which may result in some nodes being visited multiple times or not at all.

+ +

Querying Nodes

+ +

If you’re trying to locate certain nodes to perform actions on them, querying the nodes from the AST might be easier to implement. This can be done with the Query class:

+ +
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Query;
+
+// Find all paragraphs and blockquotes that contain links
+$matchingNodes = (new Query())
+    ->where(Query::type(Paragraph::class))
+    ->orWhere(Query::type(BlockQuote::class))
+    ->andWhere(Query::hasChild(Query::type(Link::class)))
+    ->findAll($document);
+
+foreach ($matchingNodes as $node) {
+    // TODO: Do something with them
+}
+
+ +

Each condition passed into where(), orWhere(), or andWhere() must be a callable “filter” that accepts a Node and returns true or false. We provide several methods that can help create these filters for you:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Query::type(string $class)Creates a filter that matches nodes with the given class name
Query::hasChild()Creates a filter that matches nodes which contain at least one child
Query::hasChild(callable $condition)Creates a filter that matches nodes which contain at least one child that matches the inner $condition
Query::hasParent()Creates a filter that matches nodes which have a parent
Query::hasParent(callable $condition)Creates a filter that matches nodes which have a parent that matches the inner $condition
+ +

You can of course create your own custom filters/conditions using an anonymous function or by implementing ExpressionInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Node\Query;
+use League\CommonMark\Node\Query\ExpressionInterface;
+
+class ChildCountGreaterThan implements ExpressionInterface
+{
+    private $count;
+
+    public function __construct(int $count)
+    {
+        $this->count = $count;
+    }
+
+    public function __invoke(Node $node) : bool{
+        return count($node->children()) > $this->count;
+    }
+}
+
+$query = (new Query())
+    ->where(function (Node $node): bool { return $node->data->has('attributes/class'); })
+    ->andWhere(new ChildCountGreaterThan(3));
+
+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ +

Data Storage

+ +

Each Node has a property called data which is a Data (array-like) object. This can be used to store any arbitrary data you’d like on the node:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text1 = new Text('Hello, world!');
+$text1->data->set('language', 'English');
+$text1->data->set('is_good_translation', true);
+
+$text2 = new Text('Bonjour monde!');
+$text2->data->set('language', 'French');
+$text2->data->set('is_good_translation', false);
+
+foreach ([$text1, $text2] as $text) {
+    if ($text->data->get('is_good_translation')) {
+        sprintf('In %s we would say: "%s"', $text->data->get('language'), $text->getLiteral());
+    } else {
+        sprintf('I think they would say "%s" in %s, but I\'m not sure.', $text->getLiteral(), $text->data->get('language'));
+    }
+}
+
+ +

You can also access deeply-nested paths using / or . as delimiters:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text = new Text('Hello, world!');
+$text->data->set('info', ['language' => 'English', 'is_good_translation' => true]);
+
+var_dump($text->data->get('info/language'));
+var_dump($text->data->get('info.is_good_translation'));
+
+$text->data->set('info/is_example', true);
+
+ +

HTML Attributes

+ +

The data property comes pre-instantiated with a single data element called attributes which is used to store any HTML attributes that need to be rendered. For example:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+$link = new Link('https://twitter.com/colinodell', '@colinodell');
+$link->data->append('attributes/class', 'social-link');
+$link->data->append('attributes/class', 'twitter');
+$link->data->set('attributes/target', '_blank');
+$link->data->set('attributes/rel', 'noopener');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/block-parsing/index.html b/2.2/customization/block-parsing/index.html new file mode 100644 index 0000000000..d4a9ce3f6f --- /dev/null +++ b/2.2/customization/block-parsing/index.html @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

At a high level, block parsing is a two-step process:

+ +
    +
  1. Using a BlockStartParserInterface to identify if/where a block start exists on the given line
  2. +
  3. Using a BlockContinueParserInterface to perform additional processing of the identified block
  4. +
+ +

So to implement a custom block parser you will actually need to implement both of these classes.

+ +

BlockStartParserInterface

+ +

Instances of this interface have a single tryStart() method:

+ +
/**
+ * Check whether we should handle the block at the current position
+ *
+ * @param Cursor                       $cursor
+ * @param MarkdownParserStateInterface $parserState
+ *
+ * @return BlockStart|null
+ */
+public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart;
+
+ +

Given a Cursor at the current position, plus some extra information about the state of the parser, this method is responsible for determining whether a particular type of block seems to exist at the given position. You don’t actually parse the block here - that’s the job of a BlockContinueParserInterface. Your only job here is to return whether or not a particular type of block does exist here, and if so which block parser should parse it.

+ +

If you find that you cannot parse the given block, you should return BlockStart::none(); from this function.

+ +

However, if the Markdown at the current position does indeed seem to be the type of block you’re looking for, you should return a BlockStart instance using the following static constructor pattern:

+ +
use League\CommonMark\Parser\Block\BlockStart;
+
+return BlockStart::of(new MyCustomParser())->at($cursor);
+
+ +

Unlike in 1.x, the Cursor state is no longer shared between parsers. You must therefore explicitly provide the BlockStart object with a copy of your cursor at the correct, post-parsing position.

+ +

NOTE: If your custom block starts with a letter character you’ll need to add your parser to the environment with a priority of 250 or higher. This is due to a performance optimization where such lines are usually skipped.

+ +

BlockContinueParserInterface

+ +

The previous interface only helps the engine identify where a block starts. Additional information about the block, as well as the ability to parse additional lines of input, is all handled by the BlockContinueParserInterface.

+ +

This interface has several methods, so it’s usually easier to extend from AbstractBlockContinueParser instead, which sets most of the methods to use typical defaults you can override as needed.

+ +

getBlock()

+ +
public function getBlock(): AbstractBlock;
+
+ +

Each instance of a BlockContinueParserInterface is associated with a new block that is being parsed. This method here returns that block.

+ +

isContainer()

+ +
public function isContainer(): bool;
+
+ +

This method returns whether or not the block is a “container” capable of containing other blocks as children.

+ +

canContain()

+ +
public function canContain(AbstractBlock $childBlock): bool;
+
+ +

This method returns whether the current block being parsed can contain the given child block.

+ +

canHaveLazyContinuationLines()

+ +
public function canHaveLazyContinuationLines(): bool;
+
+ +

This method returns whether or not this parser should also receive subsequent lines of Markdown input. This is primarily used when a block can span multiple lines, like code blocks do.

+ +

addLine()

+ +
public function addLine(string $line): void;
+
+ +

If canHaveLazyContinuationLines() returned true, this method will be called with the additional lines of content.

+ +

tryContinue()

+ +
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue;
+
+ +

This method allows you to try and parse an additional line of Markdown.

+ +

closeBlock()

+ +
public function closeBlock(): void;
+
+ +

This method is called when the block is done being parsed. Any final adjustments to the block should be made at this time.

+ +

parseInlines()

+ +
public function parseInlines(InlineParserEngineInterface $inlineParser): void;
+
+ +

This method is called when the engine is ready to parse any inline child elements.

+ +

Note: For performance reasons, this method is not part of BlockContinueParserInterface. If your block may contain inlines, you should make sure that your “continue parser” also implements BlockContinueParserWithInlinesInterface.

+ +

Tips

+ +

Here are some additional tips to consider when writing your own custom parsers:

+ +

Combining both into one file

+ +

Although parsing requires two classes, you can use the anonymous class feature of PHP to combine both into a single file! Here’s an example:

+ +
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+
+final class MyCustomBlockParser extends AbstractBlockContinueParser
+{
+    // TODO: implement your continuation parsing methods here
+
+    public static function createBlockStartParser(): BlockStartParserInterface
+    {
+        return new class implements BlockStartParserInterface
+        {
+            // TODO: implement the tryStart() method here
+        };
+    }
+}
+
+
+ +

Performance

+ +

The BlockStartParserInterface::tryStart() and BlockContinueParserInterface::tryContinue() methods may be called hundreds or thousands of times during execution. For best performance, have your methods return as early as possible, and make sure your code is highly optimized.

+ +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

If your block contains literal strings/text within the block (and not as part of a child block), you should have your custom block type also implement StringContainerInterface.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/configuration/index.html b/2.2/customization/configuration/index.html new file mode 100644 index 0000000000..3cc650131c --- /dev/null +++ b/2.2/customization/configuration/index.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Configuration Schemas and Values

+ +

Version 2.0 introduced a new robust system for defining configuration schemas and accessing them within custom extensions.

+ +

Configuration Schemas

+ +

Unlike in 1.x, all configuration options must have a defined schema. This defines which options are available, what types of values they accept, whether any are required, and any default values you wish to define if the user doesn’t provide any.

+ +

These custom options can be defined from within your custom extension by implementing the ConfigurableExtensionInterface:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+use Nette\Schema\Expect;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        $builder->addSchema('my_extension', Expect::structure([
+            'enable_some_feature' => Expect::bool()->default(true),
+            'html_class' => Expect::string()->default('my-custom-extension'),
+            'align' => Expect::anyOf('left', 'center', 'right')->default('left'),
+            'favorite_number' => Expect::int()->min(1)->max(100)->default(42),
+        ]));
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        // TODO: Implement register() method
+    }
+}
+
+ +

See the league/config documentation for more examples of how to define custom configuration schemas.

+ +

Note that you only need to implement ConfigurableExtensionInterface if you plan to define new configuration options - you don’t need this if you’re only reading existing options.

+ +

Reading Configuration Values

+ +

Okay, so your extension has defined the different options that are available, but now you want to start using them within your custom extension. There are a few ways you can access the values:

+ +

During Extension Registration

+ +

Perhaps your extension needs to decide whether/how to register certain parsers/renderers/etc based on the user-provided configuration values - in that case, you can read the value from the $environment - for example:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        // (see code example above)
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        if ($environment->getConfiguration()->get('my_extension/enable_some_feature')) {
+            $environment->addBlockStartParser(new MyCustomParser());
+            $environment->addRenderer(MyCustomBlockType::class, new MyCustomRenderer());
+        }
+    }
+}
+
+ +

Within Parsers/Renderers/Listeners

+ +

Perhaps you want to reference those configuration values from within a custom parser, renderer, event listener, or something else. This can easily by done by having that class also implement ConfigurationAwareInterface. This interface signals to the Environment that your class needs a copy of the final configuration so it can read it later:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+
+final class MyCustomRenderer implements NodeRendererInterface, ConfigurationAwareInterface
+{
+    /**
+     * @var ConfigurationInterface
+     */
+    private $config;
+
+    public function setConfiguration(ConfigurationInterface $configuration): void
+    {
+        $this->config = $configuration;
+    }
+
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return 'My favorite number is ' . $this->config->get('my_extension/favorite_number');
+    }
+}
+
+ +

You can access any configuration value from here, not just the ones you might have defined yourself.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/cursor/index.html b/2.2/customization/cursor/index.html new file mode 100644 index 0000000000..f0957ca522 --- /dev/null +++ b/2.2/customization/cursor/index.html @@ -0,0 +1,539 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Parser\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter(int $index)Returns the character at the given absolute position
getCurrentCharacter()Returns the character at the current position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/delimiter-processing/index.html b/2.2/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..65832e1872 --- /dev/null +++ b/2.2/customization/delimiter-processing/index.html @@ -0,0 +1,498 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis;
+
+// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
use League\CommonMark\Delimiter\Delimiter;
+use League\CommonMark\Node\Inline\Text;
+
+$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/environment/index.html b/2.2/customization/environment/index.html new file mode 100644 index 0000000000..bf23495d8c --- /dev/null +++ b/2.2/customization/environment/index.html @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all extensions, parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

An empty Environment can be obtained like this:

+ +
use League\CommonMark\Environment\Environment;
+
+$config = [];
+$environment = new Environment($config);
+
+ +

You can customize the Environment using any of the methods below (from the EnvironmentBuilderInterface interface).

+ +

Once your Environment is configured with whatever configuration and extensions you want, you can instantiate a MarkdownConverter and start converting MD to HTML:

+ +
use League\CommonMark\MarkdownConverter;
+
+// Using $environment from the previous code sample
+$converter = new MarkdownConverter($environment);
+
+echo $converter->convert('# Hello World!');
+
+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. For example, if you want core CommonMark functionality plus footnote support:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+$config = [];
+$environment = new Environment($config);
+
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new FootnoteExtension());
+
+ +

addBlockStartParser()

+ +
public function addBlockStartParser(BlockStartParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockStartParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addRenderer()

+ +
public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0);
+
+ +

Registers a NodeRendererInterface to handle a specific type of AST node ($nodeClass) with the given priority (a higher number will be executed earlier).

+ +

See Rendering for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/event-dispatcher/index.html b/2.2/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..12fcb21bbc --- /dev/null +++ b/2.2/customization/event-dispatcher/index.html @@ -0,0 +1,574 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic, PSR-14-compliant event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code.

+ +

Event Class

+ +

Any PSR-14 compliant event can be used, though we also provide an AbstractEvent class you can use to easily create your own events:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - the event object to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

League\CommonMark\Event\DocumentPreRenderEvent

+ +

This event is dispatched by the renderer just before rendering begins. Like with DocumentParsedEvent, this offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering, but with the added knowledge of which format is being rendered to (e.g. html).

+ +

League\CommonMark\Event\DocumentRenderedEvent

+ +

This event is dispatched once the rendering step has been completed, just before the output is returned. The final output can be adjusted at this point or additional metadata can be attached to the return object.

+ +

Bring Your Own PSR-14 Event Dispatcher

+ +

Although this library provides PSR-14 compliant event dispatching out-of-the-box, you may want to use your own PSR-14 event dispatcher instead. This is possible as long as that third-party library both:

+ +
    +
  1. Implements the PSR-14 EventDispatcherInterface; and,
  2. +
  3. Allows you to register additional ListenerProviderInterface instances with that dispatcher library
  4. +
+ +

Not all libraries support this so please check carefully! Assuming yours does, delegating all the event behavior to that library can be done with two steps:

+ +

First, call the setEventDispatcher() method on the Environment to register that other implementation. With that done, any calls to Environment::dispatch() will be passed through to that other dispatcher. But we still need to let that dispatcher know about the events registered by CommonMark extensions, otherwise nothing will happen when events are dispatched.

+ +

Because the Environment implements PSR-14’s ListenerProviderInterface you’ll also need to pass the configured Environment object to your event dispatcher so that it becomes aware of those available events.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event): void
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data->append('attributes/class', 'external-link');
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfiguration()->get('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = new Environment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convert($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/extensions/index.html b/2.2/customization/extensions/index.html new file mode 100644 index 0000000000..2a8bec1c3a --- /dev/null +++ b/2.2/customization/extensions/index.html @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a EnvironmentBuilderInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new EmojiExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/inline-parsing/index.html b/2.2/customization/inline-parsing/index.html new file mode 100644 index 0000000000..b4c4f230e0 --- /dev/null +++ b/2.2/customization/inline-parsing/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getMatchDefinition()

+ +

This method should return an instance of InlineParserMatch which defines the text the parser is looking for. Examples of this might be something like:

+ +
use League\CommonMark\Parser\Inline\InlineParserMatch;
+
+InlineParserMatch::string('@');                  // Match any '@' characters found in the text
+InlineParserMatch::string('foo');                // Match the text 'foo' (case insensitive)
+
+InlineParserMatch::oneOf('@', '!');              // Match either character
+InlineParserMatch::oneOf('http://', 'https://'); // Match either string
+
+InlineParserMatch::regex('\d+');                 // Match the regular expression (omit the regex delimiters and any flags)
+
+ +

Once a match is found, the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has found at a matching string in the current line; and,
  2. +
  3. No other inline parsers with a higher priority have successfully parsed the text at this point in the line
  4. +
+ +

Parameters

+ + + +
InlineParserContext
+ +

This class has several useful methods:

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the text at the current position for any reason. Other parsers will then have a chance to try parsing that text. If all registered parsers return false, the text will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed/matched text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::regex('@([A-Za-z0-9_]{1,15}(?!\w))');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+
+        // This seems to be a valid match
+        // Advance the cursor to the end of the match
+        $cursor->advanceBy($inlineContext->getFullMatchLength());
+
+        // Grab the Twitter handle
+        [$handle] = $inlineContext->getSubMatches();
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+// And here's how to hook it up:
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::oneOf(':)', ':(');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($inlineContext->getFullMatch() === ':)') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($inlineContext->getFullMatch() === ':(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/overview/index.html b/2.2/customization/overview/index.html new file mode 100644 index 0000000000..b870b50ee2 --- /dev/null +++ b/2.2/customization/overview/index.html @@ -0,0 +1,479 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders/configuration you need
  2. +
  3. Instantiate a MarkdownParser and HtmlRenderer using that Environment
  4. +
  5. Use the MarkdownParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  6. +
  7. Use the HtmlRenderer to convert the AST Document into HTML
  8. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+$environment = new Environment([
+    'html_input' => 'strip',
+]);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderDocument($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renderers convert the parsed blocks/inlines from the AST representation into HTML. When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/rendering/index.html b/2.2/customization/rendering/index.html new file mode 100644 index 0000000000..5fa97bf334 --- /dev/null +++ b/2.2/customization/rendering/index.html @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Custom Rendering

+ +

Renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement NodeRendererInterface and its render() method. Note that in v2.0, both +block renderers and inline renderers share the same interface and method:

+ +

render()

+ +
public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The HtmlRenderer will call this method during the rendering process whenever a supported element is encountered.

+ +

If your renderer can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the node and its contents, including any children. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\Util\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Renderers

+ +

When registering your renderer, you must tell the Environment which node element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// First param - the node class type that should use our renderer
+// Second param - instance of the renderer
+$environment->addRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple types:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak;
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements NodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(ThematicBreak::class, new TextDividerRenderer());
+
+ +

Note that thematic breaks should not contain children, which is why the $childRenderer is unused in this example. Otherwise we’d have to call code like this and return the result as part of the rendered HTML we’re generating here: $innerHtml = $childRenderer->renderNodes($node->children());

+ +

Tips

+ + + +

Wrapping Elements with HtmlDecorator

+ +

A utility class called HtmlDecorator is provided to make it easier to wrap the output of any renderer within an additional HTML tag with custom attributes and/or classes.

+ +

To use it, you register it as a renderer for whatever AST node type you want to wrap:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\Table\TableRenderer;
+use League\CommonMark\Renderer\HtmlDecorator;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new TableExtension());
+$environment->addRenderer(Table::class, new HtmlDecorator(new TableRenderer(), 'div', ['class' => 'table-responsive']));
+
+ +

XML Rendering

+ +

The XML renderer will automatically attempt to convert any AST nodes to XML by inspecting the name of the block/inline node and its attributes. You can instead control the XML element name and attributes by making your renderer implement XmlNodeRendererInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+
+class TextDividerRenderer implements NodeRendererInterface, XmlNodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+
+    public function getXmlTagName(Node $node): string
+    {
+        return 'text_divider';
+    }
+
+    public function getXmlAttributes(Node $node): array
+    {
+        return ['character' => '='];
+    }
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/customization/slug-normalizer/index.html b/2.2/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..65723c7361 --- /dev/null +++ b/2.2/customization/slug-normalizer/index.html @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + Slug Normalizer - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Slug Normalizer

+ +

“Slugs” are strings used within href, name, and id HTML attributes to identify particular elements within a document.

+ +

Some extensions (like the HeadingPermalinkExtension) need the ability to convert user-provided text into these URL-safe slugs while also ensuring that these are unique throughout the generated HTML. The Environment provides a pre-built normalizer you can use for this purpose.

+ +

Usage

+ +

You can obtain a reference to the built-in slug normalizer by calling $environment->getSlugNormalizer();

+ +

To use this within your extension, have your parser/renderer/whatever implement EnvironmentAwareInterface and then implement the corresponding setEnvironment method like this:

+ +

+use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Environment\EnvironmentAwareInterface;
+
+class MyCustomParserOrRenderer implements EnvironmentAwareInterface
+{
+    private $slugNormalizer;
+
+    public function setEnvironment(EnvironmentInterface $environment): void
+    {
+        $this->slugNormalizer = $environment->getSlugNormalizer();
+    }
+}
+
+ +

You can then call $this->slugNormalizer->normalize($text) as needed.

+ +

Configuration

+ +

The slug_normalizer configuration section allows you to adjust the following options:

+ +

instance

+ +

You can change the string that is used as the “slug” by setting the instance option to any class that implements TextNormalizerInterface. +We provide a simple SlugNormalizer by default, but you may want to plug in a different library or create your own normalizer instead.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

max_length

+ +

This can be configured to limit the length of that slug to prevent overly-long values. By default, that limit is 255 characters. You may set this to any positive integer, or 0 for no limit.

+ +

(Note that generated slugs might be slightly longer than this “limit” if the unique option is enabled and the slug generator detects a duplicate slug and needs to add a suffix to make it unique.)

+ +

unique

+ +

This options controls whether slugs should be unique. Possible values include:

+ + + +

You might have a use case where you’re converting several different Markdown documents on the same page and so you’d like to ensure that none of those documents use conflicting slugs. In that case, you should set the scope option to 'environment' to ensure that a single instance of a MarkdownConverter (which uses a single Environment) will never produce the same slug twice during its lifetime (which usually lasts the entire duration of a single HTTP request).

+ +

If you need complete control over how unique slugs are generated, make your 'instance' implement UniqueSlugNormalizerInterface; otherwise, we’ll simply append incremental numbers to slugs to ensure they are unique.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/attributes/index.html b/2.2/extensions/attributes/index.html new file mode 100644 index 0000000000..0bbe94a50f --- /dev/null +++ b/2.2/extensions/attributes/index.html @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+ +

This results in the following output:

+ +
<blockquote title="Blockquote title">
+<p>A nice blockquote</p>
+</blockquote>
+
+ +

CSS-selector-style declarations can be used to set the id and class attributes:

+ +
{#id .class}
+## Header
+
+ +

Output:

+ +
<h2 class="class" id="id">Header</h2>
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Output:

+ +
<p>This is <em style="color: red">red</em>.</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/autolinks/index.html b/2.2/extensions/autolinks/index.html new file mode 100644 index 0000000000..7ce1e1ad1d --- /dev/null +++ b/2.2/extensions/autolinks/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a Mention Parser outside of this extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/commonmark/index.html b/2.2/extensions/commonmark/index.html new file mode 100644 index 0000000000..8521c90d7b --- /dev/null +++ b/2.2/extensions/commonmark/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically installed for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new Environment with the core extension
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/default-attributes/index.html b/2.2/extensions/default-attributes/index.html new file mode 100644 index 0000000000..c6dd5ce0a3 --- /dev/null +++ b/2.2/extensions/default-attributes/index.html @@ -0,0 +1,519 @@ + + + + + + + + + + + + + + + + + Default Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Default Attributes

+ +

The DefaultAttributesExtension allows you to apply default HTML classes and other attributes using configuration options.

+ +

It works by applying the attributes to the nodes during the DocumentParsedEvent event - right after the nodes are parsed but before they are rendered. +(As a result, it’s possible that renderers may add other attributes - the goal of this extension is only to provide custom defaults.)

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DefaultAttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Node\Block\Paragraph;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'default_attributes' => [
+        Heading::class => [
+            'class' => static function (Heading $node) {
+                if ($node->getLevel() === 1) {
+                    return 'title-main';
+                } else {
+                    return null;
+                }
+            },
+        ],
+        Table::class => [
+            'class' => 'table',
+        ],
+        Paragraph::class => [
+            'class' => ['text-center', 'font-comic-sans'],
+        ],
+        Link::class => [
+            'class' => 'btn btn-link',
+            'target' => '_blank',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new DefaultAttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a default_attributes array. Each key in the array should be a FQCN for the node class you wish to apply the default attribute to, and the values should be a map of attribute names to attribute values.

+ +

Attribute values may be any of the following types:

+ + + +

Examples

+ +

Here’s an example that will apply Bootstrap 4 classes and attributes:

+ +
$config = [
+    'default_attributes' => [
+        Table::class => [
+            'class' => ['table', 'table-responsive'],
+        ],
+        BlockQuote::class => [
+            'class' => 'blockquote',
+        ],
+    ],
+];
+
+ +

Here’s a more complex example that uses a callable to add a class only if the paragraph immediately follows an <h1> heading:

+ +
$config = [
+    'default_attributes' => [
+        Paragraph::class => [
+            'class' => static function (Paragraph $paragraph) {
+                if ($paragraph->previous() instanceof Heading && $paragraph->previous()->getLevel() === 1) {
+                    return 'lead';
+                }
+
+                return null;
+            },
+        ],
+    ],
+];
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/description-lists/index.html b/2.2/extensions/description-lists/index.html new file mode 100644 index 0000000000..d3728db3af --- /dev/null +++ b/2.2/extensions/description-lists/index.html @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + + Description List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Description List Extension

+ +

The DescriptionListExtension adds Markdown Extra-style description lists to facilitate the creation of <dl>, <dt>, and <dd> HTML using Markdown.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DescriptionListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\DescriptionList\DescriptionListExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DescriptionListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some markdown goes here');
+
+ +

Syntax

+ +

The syntax is based directly on the rules and logic implemented by the Markdown Extra library. Here are some examples of sample Markdown input and HTML output demonstrating the syntax:

+ +
Apple
+:   Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.
+:   An American computer company.
+
+Orange
+:   The fruit of an evergreen tree of the genus Citrus.
+
+ +
<dl>
+    <dt>Apple</dt>
+    <dd>Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.</dd>
+    <dd>An American computer company.</dd>
+
+    <dt>Orange</dt>
+    <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+
+ +

See the Markdown Extra documentation or our own spec for additional examples.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/disallowed-raw-html/index.html b/2.2/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..fc6952f415 --- /dev/null +++ b/2.2/extensions/disallowed-raw-html/index.html @@ -0,0 +1,476 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically escapes certain HTML tags when rendering raw HTML, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Customize the extension's configuration if needed
+// Default values are shown below - you can omit this configuration if you're happy with those defaults
+// and don't want to customize them
+$config = [
+    'disallowed_raw_html' => [
+        'disallowed_tags' => ['title', 'textarea', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'script', 'plaintext'],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I cannot change the page <title>anymore</title>');
+
+ +

Configuration

+ +

This extension can be configured by providing a disallowed_raw_html array with the following nested configuration options. The defaults are shown in the code example above.

+ +

disallowed_tags

+ +

An array containing a list of tags that should be escaped.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/external-links/index.html b/2.2/extensions/external-links/index.html new file mode 100644 index 0000000000..f80da79e75 --- /dev/null +++ b/2.2/extensions/external-links/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class MyCustomLinkRenderer implements NodeRendererInterface
+{
+    /**
+     * @param Node                       $node
+     * @param ChildNodeRendererInterface $childRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        if (!($node instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible node type: ' . \get_class($node));
+        }
+
+        if ($node->data->get('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/footnotes/index.html b/2.2/extensions/footnotes/index.html new file mode 100644 index 0000000000..399f14c5f8 --- /dev/null +++ b/2.2/extensions/footnotes/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1"></a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'backref_symbol'     => '↩',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

backref_symbol

+ +

This string option sets the symbol used as the contents of the footnote backreference link. It defaults to \League\CommonMark\Extension\Footnote\Renderer\FootnoteBackrefRenderer::DEFAULT_SYMBOL = '↩'.

+ +

If you want to use a custom icon, set this to an empty string '' and take a look at the Adding Icons section below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ +

Adding Icons

+ +

You can use CSS to add a custom icon instead of providing a backref_symbol:

+ +
$config = [
+    'footnote' => [
+        'backref_class' => 'footnote-backref',
+        'backref_symbol' => '',
+    ],
+];
+
+ +

Then target the backref_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.footnote-backref::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/front-matter/index.html b/2.2/extensions/front-matter/index.html new file mode 100644 index 0000000000..d1d70780c1 --- /dev/null +++ b/2.2/extensions/front-matter/index.html @@ -0,0 +1,542 @@ + + + + + + + + + + + + + + + + + Front Matter Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Front Matter Extension

+ +

The FrontMatterExtension adds the ability to parse YAML front matter from the Markdown document and include that in the return result.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

You will also need to install symfony/yaml or the YAML extension for PHP to use this extension. For symfony/yaml:

+ +
composer require symfony/yaml
+
+ +

(You can use any version of symfony/yaml 2.3 or higher, though we recommend using 4.0 or higher.)

+ +

Front Matter Syntax

+ +

This extension follows the Jekyll Front Matter syntax. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:

+ +
---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+
+ +

This will produce a front matter array similar to this:

+ +
$parsedFrontMatter = [
+    'layout' => 'post',
+    'title' => 'I Love Markdown',
+    'tags' => [
+        'test',
+        'example',
+    ],
+];
+
+ +

And the HTML output will only contain the one heading:

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

Usage

+ +

Configure your Environment as usual and add the FrontMatterExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FrontMatterExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+// A sample Markdown file with some front matter:
+$markdown = <<<MD
+---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+MD;
+
+$result = $converter->convert($markdown);
+
+// Grab the front matter:
+if ($result instanceof RenderedContentWithFrontMatter) {
+    $frontMatter = $result->getFrontMatter();
+}
+
+// Output the HTML using any of these:
+echo $result;               // implicit string cast
+// or:
+echo (string) $result;      // explicit string cast
+// or:
+echo $result->getContent();
+
+ +

Parsing Front Matter Only

+ +

You don’t have to parse the entire file (including all the Markdown) if you only want the front matter. You can either instantiate the front matter parser yourself and call it directly, like this:

+ +
use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+// For `symfony/yaml`
+$frontMatterParser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
+// For YAML extension
+$frontMatterParser = new FrontMatterParser(new LibYamlFrontMatterParser());
+$result = $frontMatterParser->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

Or you can use the getFrontMatterParser() method from the extension:

+ +
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+$frontMatterExtension = new FrontMatterExtension();
+$result = $frontMatterExtension->getFrontMatterParser()->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

This latter approach may be more convenient if you have already instantiated a FrontMatterExtension object you’re adding to the Environment somewhere and just want to call that.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/github-flavored-markdown/index.html b/2.2/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..0ccd5c4816 --- /dev/null +++ b/2.2/extensions/github-flavored-markdown/index.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark and GFM parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/heading-permalinks/index.html b/2.2/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..d969879dd4 --- /dev/null +++ b/2.2/extensions/heading-permalinks/index.html @@ -0,0 +1,615 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'content',
+        'fragment_prefix' => 'content',
+        'insert' => 'before',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'aria_hidden' => true,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

fragment_prefix

+ +

This should be a string you want prepended to the URL fragment in the link’s href attribute. This should typically be set to the same value as id_prefix for links to work properly. However, you may not want to expose that same prefix in your URLs - in that case, you can set this to something different (even an empty string) and use JavaScript to “rewrite” them.

+ +

For example, to emulate how GitHub heading permalinks work, set id_prefix to 'user-content', set fragment_prefix to '', and insert some JavaScript into the page like this:

+ +
var scrollToPermalink = function() {
+    var link = document.getElementById('user-content-' + window.location.hash);
+    if (link) {
+        link.scrollIntoView({behavior: 'smooth'});
+    }
+};
+
+window.addEventListener('hashchange', scrollToPermalink);
+if (window.location.hash) {
+    scrollToPermalink();
+}
+
+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

min_heading_level and max_heading_level

+ +

These two settings control which headings should have permalinks added. By default, all 6 levels (1, 2, 3, 4, 5, and 6) will have them. You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

aria_hidden

+ +

This option sets the aria-hidden attribute on the <a> tag. This defaults to aria-hidden="true".

+ +

Setting this option to false would render the <a> tag excluding the aria-hidden entirely.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/inlines-only/index.html b/2.2/extensions/inlines-only/index.html new file mode 100644 index 0000000000..d9d1363010 --- /dev/null +++ b/2.2/extensions/inlines-only/index.html @@ -0,0 +1,440 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new, empty environment
+$environment = new Environment($config);
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/mentions/index.html b/2.2/extensions/mentions/index.html new file mode 100644 index 0000000000..3e08a04096 --- /dev/null +++ b/2.2/extensions/mentions/index.html @@ -0,0 +1,666 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting prefix, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the first mention parser to
+        // successfully match and return a properly constructed Mention object (where the URL has been set) will be the
+        // the mention parser that is used. In this example, the GitHub handle would actually match first because
+        // there isn't any real validation to check whether https://www.github.com/colinodell exists. However, in
+        // CMS applications, you could check whether its a local user first, then check Twitter and then GitHub, etc.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on GitHub: @colinodell');
+// Output:
+// <p>Follow me on GitHub: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regular expression pattern (without opening/closing delimiter or modifiers), or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Inline\Element\AbstractInline;
+
+class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/overview/index.html b/2.2/extensions/overview/index.html new file mode 100644 index 0000000000..9a300669f2 --- /dev/null +++ b/2.2/extensions/overview/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Default AttributesEasily apply default HTML classes using configuration options to match your site’s styles2.0.0 
Description ListsCreate <dl> description lists using Markdown Extra’s syntax2.0.0 
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
Front MatterParses YAML front matter from your Markdown input2.0.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the extensions you need
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the other extensions you need
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/smart-punctuation/index.html b/2.2/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..9bff886f36 --- /dev/null +++ b/2.2/extensions/smart-punctuation/index.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/strikethrough/index.html b/2.2/extensions/strikethrough/index.html new file mode 100644 index 0000000000..670e9fed16 --- /dev/null +++ b/2.2/extensions/strikethrough/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/table-of-contents/index.html b/2.2/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..10aeaae62e --- /dev/null +++ b/2.2/extensions/table-of-contents/index.html @@ -0,0 +1,597 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
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;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/tables/index.html b/2.2/extensions/tables/index.html new file mode 100644 index 0000000000..6e7f37cd61 --- /dev/null +++ b/2.2/extensions/tables/index.html @@ -0,0 +1,522 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => false,
+            'tag' => 'div',
+            'attributes' => [],
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Configuration

+ +

Wrapping Container

+ +

You can “wrap” the table with a container element by configuring the following options:

+ + + +

For example, to wrap all tables within a <div class="table-responsive"> container element:

+ +
$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => true,
+            'tag' => 'div',
+            'attributes' => ['class' => 'table-responsive'],
+        ],
+    ],
+];
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/extensions/task-lists/index.html b/2.2/extensions/task-lists/index.html new file mode 100644 index 0000000000..372b4dac17 --- /dev/null +++ b/2.2/extensions/task-lists/index.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convert($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/index.html b/2.2/index.html new file mode 100644 index 0000000000..5b92ea1cba --- /dev/null +++ b/2.2/index.html @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello, World!')->getContent();
+
+// <h1>Hello, World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/installation/index.html b/2.2/installation/index.html new file mode 100644 index 0000000000..9cf612f7ce --- /dev/null +++ b/2.2/installation/index.html @@ -0,0 +1,418 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +
composer require "league/commonmark:^2.2"
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^2.2. This is equivalent to >=2.2 <3.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/security/index.html b/2.2/security/index.html new file mode 100644 index 0000000000..98a43396f8 --- /dev/null +++ b/2.2/security/index.html @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convert($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/support/index.html b/2.2/support/index.html new file mode 100644 index 0000000000..f8b32c4765 --- /dev/null +++ b/2.2/support/index.html @@ -0,0 +1,425 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/upgrading/index.html b/2.2/upgrading/index.html new file mode 100644 index 0000000000..aa463c4fb3 --- /dev/null +++ b/2.2/upgrading/index.html @@ -0,0 +1,412 @@ + + + + + + + + + + + + + + + + + Upgrading from 2.1 to 2.2 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 2.1 to 2.2

+ +

Deprecation of MarkdownConverterInterface

+ +

The MarkdownConverterInterface and its convertToHtml() method were deprecated in 2.2.0 and will be removed in 3.0.0. +You should switch your implementations to use ConverterInterface and convert() instead which provide the same behavior.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.2/xml/index.html b/2.2/xml/index.html new file mode 100644 index 0000000000..bf32b96374 --- /dev/null +++ b/2.2/xml/index.html @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + XML Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.2. Please consider upgrading your code to the latest stable version

+ + +

XML Rendering

+ +

Version 2.0 introduced the ability to render Markdown Document objects in XML. This is particularly useful for debugging custom extensions as you can see the XML representation of the Abstract Syntax Tree.

+ +

To convert Markdown to XML, you would instantiate a MarkdownToXmlConverter with an Environment and then call convert() on any Markdown.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Xml\MarkdownToXmlConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$converter = new MarkdownToXmlConverter($environment);
+
+echo $converter->convert('# **Hello** World!');
+
+ +

This will display XML output like this:

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<document xmlns="http://commonmark.org/xml/1.0">
+    <heading level="1">
+        <strong>
+            <text>Hello</text>
+        </strong>
+        <text> World!</text>
+    </heading>
+</document>
+
+ +

Alternatively, if you already have a Document object you want to visualize in XML, you can use theXmlRenderer class to convert it to XML.

+ +

Return Value

+ +

Like with CommonMarkConverter::convert(), the renderDocument() actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final XML output.

+ +

Customizing the XML Output

+ +

See the rendering documentation for information on customizing the XML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/basic-usage/index.html b/2.3/basic-usage/index.html new file mode 100644 index 0000000000..6b5aa2cbb0 --- /dev/null +++ b/2.3/basic-usage/index.html @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Basic Usage

+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Using Extensions

+ +

The CommonMarkConverter and GithubFlavoredMarkdownConverter shown above automatically configure the environment for you, but if you want to use additional extensions you’ll need to avoid those classes and use the generic MarkdownConverter class instead to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

Configuration

+ +

If you’re using the CommonMarkConverter or GithubFlavoredMarkdownConverter class you can pass configuration options directly into their constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

See the configuration section for more information on the available configuration options.

+ +

Supported Character Encodings

+ +

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.

+ +

Return Value

+ +

The convert() method actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final HTML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/changelog/index.html b/2.3/changelog/index.html new file mode 100644 index 0000000000..a3acb61f5d --- /dev/null +++ b/2.3/changelog/index.html @@ -0,0 +1,722 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Changelog

+ +

All notable changes made in 2.x releases are shown below. See the full list of releases for the complete changelog.

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

2.4.4 - 2024-07-22

+ +

Fixed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

+ +

2.4.3 - 2024-07-22

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.2…2.4.3

+ +

2.4.2 - 2024-02-02

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.1…2.4.2

+ +

2.4.1 - 2023-08-30

+ +

Fixed

+ + + +

2.4.0 - 2023-03-24

+ +

See the upgrading guide for more information about the exception-related changes

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

2.3.9 - 2023-02-15

+ +

Fixed

+ + + +

2.3.8 - 2022-12-10

+ +

Fixed

+ + + +

2.3.7 - 2022-11-17

+ +

Fixed

+ + + +

2.3.6 - 2022-10-30

+ +

Fixed

+ + + +

2.3.5 - 2022-07-29

+ +

Fixed

+ + + +

2.3.4 - 2022-07-17

+ +

Changed

+ + + +

Fixed

+ + + +

2.3.3 - 2022-06-07

+ +

Fixed

+ + + +

2.3.2 - 2022-06-03

+ +

Fixed

+ + + +

2.3.1 - 2022-05-14

+ +

Fixed

+ + + +

2.3.0 - 2022-04-07

+ +

Added

+ + + +

Deprecated

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/configuration/index.html b/2.3/configuration/index.html new file mode 100644 index 0000000000..b3b1708e7a --- /dev/null +++ b/2.3/configuration/index.html @@ -0,0 +1,511 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the Environment or converter classes when creating them:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+    'slug_normalizer' => [
+        'max_length' => 255,
+    ],
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of the core configuration options available:

+ + + +

Additional configuration options are available for most of the available extensions - refer to their individual documentation for more details. For example, the CommonMark core extension offers these additional options:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/abstract-syntax-tree/index.html b/2.3/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..6b5e972f19 --- /dev/null +++ b/2.3/customization/abstract-syntax-tree/index.html @@ -0,0 +1,706 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Visualization

+ +

Even with an interactive debugger it can be tricky to view an entire tree at once. Consider using the XmlRenderer to provide a simple text-based representation of the AST for debugging purposes.

+ +

Node Traversal

+ +

There are four different ways to traverse/iterate the Nodes within the AST:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodProsCons
Manual TraversalBest way to access/check direct relatives of nodesNot useful for iteration
Iterating the TreeFast and efficientPossible unexpected behavior when adding/removing sibling nodes while iterating
Walking the TreeFull control over iterationUp to twice as slow as iteration; adding/removing nodes while iterating can lead to weird behaviors
Querying NodesEasier to write and understand; no weird behaviorsNot memory efficient
+ +

Each is described in more detail below

+ +

Manual Traversal

+ +

The following methods can be used to manually traverse from one Node to any of its direct relatives:

+ + + +

This is best suited for situations when you need to know information about those relatives.

+ +

Iterating the Tree

+ +

If you’d like to iterate through all the nodes, use the iterator() method to obtain an iterator that will loop through each node in the tree (using pre-order traversal):

+ +
foreach ($document->iterator() as $node) {
+    echo 'Current node: ' . get_class($node) . "\n";
+}
+
+ +

Given an AST like this (XML representation):

+ +
<document>
+  <heading level="1">
+    <text>Hello World!</text>
+  </heading>
+  <paragraph>
+    <text>This is an example of </text>
+    <strong>
+      <text>CommonMark</text>
+    </strong>
+    <text>.</text>
+  </paragraph>
+</document>
+
+ +

The code above will output:

+ +
Current node: League\CommonMark\Node\Block\Document
+Current node: League\CommonMark\Extension\CommonMark\Node\Block\Heading
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Block\Paragraph
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Extension\CommonMark\Node\Inline\Strong
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Inline\Text
+
+ +

This iterator doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes. It’s also very CPU and memory-efficient.

+ +

Be careful when modifying nodes while iterating the tree as some of those changes may affect the current iteration process, especially for sibling nodes that come after the current one. For example, if you remove the current node’s next() sibling, the next loop of that iteration will still include the removed sibling even though it was successfully removed from the AST. Similarly, any new siblings that are added won’t be visited on the next loop.

+ +

Walking the Tree

+ +

If you’d like to walk through all the nodes, visiting each one as you enter and leave it, use the walker() method to obtain an instance of NodeWalker. This also uses pre-order traversal but emitting NodeWalkerEvents along the way:

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'Now ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

Using the same example AST in the previous section, this code will output:

+ +
Now entering a League\CommonMark\Node\Block\Document node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Block\Paragraph node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Node\Block\Paragraph node
+Now leaving a League\CommonMark\Node\Block\Document node
+
+ +

This approach offers many of the same benefits as the simple iteration shown in the previous section such as memory efficiency and no recursion. The key differences come from how you enter and leave nodes:

+ +
    +
  1. Iteration can potentially take twice as long - not ideal for performance
  2. +
  3. Provides you with more control over exactly when an action is taken on a node which is sometimes needed for certain AST manipulations
  4. +
  5. Also provides a resumeAt() method to override where it should iterate next
  6. +
+ +

But like with the iterator, be careful when adding/removing nodes while walking the tree, as there are even more subtle cases where the walker could even lose track of where it was, which may result in some nodes being visited multiple times or not at all.

+ +

Querying Nodes

+ +

If you’re trying to locate certain nodes to perform actions on them, querying the nodes from the AST might be easier to implement. This can be done with the Query class:

+ +
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Query;
+
+// Find all paragraphs and blockquotes that contain links
+$matchingNodes = (new Query())
+    ->where(Query::type(Paragraph::class))
+    ->orWhere(Query::type(BlockQuote::class))
+    ->andWhere(Query::hasChild(Query::type(Link::class)))
+    ->findAll($document);
+
+foreach ($matchingNodes as $node) {
+    // TODO: Do something with them
+}
+
+ +

Each condition passed into where(), orWhere(), or andWhere() must be a callable “filter” that accepts a Node and returns true or false. We provide several methods that can help create these filters for you:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Query::type(string $class)Creates a filter that matches nodes with the given class name
Query::hasChild()Creates a filter that matches nodes which contain at least one child
Query::hasChild(callable $condition)Creates a filter that matches nodes which contain at least one child that matches the inner $condition
Query::hasParent()Creates a filter that matches nodes which have a parent
Query::hasParent(callable $condition)Creates a filter that matches nodes which have a parent that matches the inner $condition
+ +

You can of course create your own custom filters/conditions using an anonymous function or by implementing ExpressionInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Node\Query;
+use League\CommonMark\Node\Query\ExpressionInterface;
+
+class ChildCountGreaterThan implements ExpressionInterface
+{
+    private $count;
+
+    public function __construct(int $count)
+    {
+        $this->count = $count;
+    }
+
+    public function __invoke(Node $node) : bool{
+        return count($node->children()) > $this->count;
+    }
+}
+
+$query = (new Query())
+    ->where(function (Node $node): bool { return $node->data->has('attributes/class'); })
+    ->andWhere(new ChildCountGreaterThan(3));
+
+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ +

Data Storage

+ +

Each Node has a property called data which is a Data (array-like) object. This can be used to store any arbitrary data you’d like on the node:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text1 = new Text('Hello, world!');
+$text1->data->set('language', 'English');
+$text1->data->set('is_good_translation', true);
+
+$text2 = new Text('Bonjour monde!');
+$text2->data->set('language', 'French');
+$text2->data->set('is_good_translation', false);
+
+foreach ([$text1, $text2] as $text) {
+    if ($text->data->get('is_good_translation')) {
+        sprintf('In %s we would say: "%s"', $text->data->get('language'), $text->getLiteral());
+    } else {
+        sprintf('I think they would say "%s" in %s, but I\'m not sure.', $text->getLiteral(), $text->data->get('language'));
+    }
+}
+
+ +

You can also access deeply-nested paths using / or . as delimiters:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text = new Text('Hello, world!');
+$text->data->set('info', ['language' => 'English', 'is_good_translation' => true]);
+
+var_dump($text->data->get('info/language'));
+var_dump($text->data->get('info.is_good_translation'));
+
+$text->data->set('info/is_example', true);
+
+ +

HTML Attributes

+ +

The data property comes pre-instantiated with a single data element called attributes which is used to store any HTML attributes that need to be rendered. For example:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+$link = new Link('https://twitter.com/colinodell', '@colinodell');
+$link->data->append('attributes/class', 'social-link');
+$link->data->append('attributes/class', 'twitter');
+$link->data->set('attributes/target', '_blank');
+$link->data->set('attributes/rel', 'noopener');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/block-parsing/index.html b/2.3/customization/block-parsing/index.html new file mode 100644 index 0000000000..2270bfc55d --- /dev/null +++ b/2.3/customization/block-parsing/index.html @@ -0,0 +1,550 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Block Parsing

+ +

At a high level, block parsing is a two-step process:

+ +
    +
  1. Using a BlockStartParserInterface to identify if/where a block start exists on the given line
  2. +
  3. Using a BlockContinueParserInterface to perform additional processing of the identified block
  4. +
+ +

So to implement a custom block parser you will actually need to implement both of these classes.

+ +

BlockStartParserInterface

+ +

Instances of this interface have a single tryStart() method:

+ +
/**
+ * Check whether we should handle the block at the current position
+ *
+ * @param Cursor                       $cursor
+ * @param MarkdownParserStateInterface $parserState
+ *
+ * @return BlockStart|null
+ */
+public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart;
+
+ +

Given a Cursor at the current position, plus some extra information about the state of the parser, this method is responsible for determining whether a particular type of block seems to exist at the given position. You don’t actually parse the block here - that’s the job of a BlockContinueParserInterface. Your only job here is to return whether or not a particular type of block does exist here, and if so which block parser should parse it.

+ +

If you find that you cannot parse the given block, you should return BlockStart::none(); from this function.

+ +

However, if the Markdown at the current position does indeed seem to be the type of block you’re looking for, you should return a BlockStart instance using the following static constructor pattern:

+ +
use League\CommonMark\Parser\Block\BlockStart;
+
+return BlockStart::of(new MyCustomParser())->at($cursor);
+
+ +

Unlike in 1.x, the Cursor state is no longer shared between parsers. You must therefore explicitly provide the BlockStart object with a copy of your cursor at the correct, post-parsing position.

+ +

NOTE: If your custom block starts with a letter character you’ll need to add your parser to the environment with a priority of 250 or higher. This is due to a performance optimization where such lines are usually skipped.

+ +

BlockContinueParserInterface

+ +

The previous interface only helps the engine identify where a block starts. Additional information about the block, as well as the ability to parse additional lines of input, is all handled by the BlockContinueParserInterface.

+ +

This interface has several methods, so it’s usually easier to extend from AbstractBlockContinueParser instead, which sets most of the methods to use typical defaults you can override as needed.

+ +

getBlock()

+ +
public function getBlock(): AbstractBlock;
+
+ +

Each instance of a BlockContinueParserInterface is associated with a new block that is being parsed. This method here returns that block.

+ +

isContainer()

+ +
public function isContainer(): bool;
+
+ +

This method returns whether or not the block is a “container” capable of containing other blocks as children.

+ +

canContain()

+ +
public function canContain(AbstractBlock $childBlock): bool;
+
+ +

This method returns whether the current block being parsed can contain the given child block.

+ +

canHaveLazyContinuationLines()

+ +
public function canHaveLazyContinuationLines(): bool;
+
+ +

This method returns whether or not this parser should also receive subsequent lines of Markdown input. This is primarily used when a block can span multiple lines, like code blocks do.

+ +

addLine()

+ +
public function addLine(string $line): void;
+
+ +

If canHaveLazyContinuationLines() returned true, this method will be called with the additional lines of content.

+ +

tryContinue()

+ +
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue;
+
+ +

This method allows you to try and parse an additional line of Markdown.

+ +

closeBlock()

+ +
public function closeBlock(): void;
+
+ +

This method is called when the block is done being parsed. Any final adjustments to the block should be made at this time.

+ +

parseInlines()

+ +
public function parseInlines(InlineParserEngineInterface $inlineParser): void;
+
+ +

This method is called when the engine is ready to parse any inline child elements.

+ +

Note: For performance reasons, this method is not part of BlockContinueParserInterface. If your block may contain inlines, you should make sure that your “continue parser” also implements BlockContinueParserWithInlinesInterface.

+ +

Tips

+ +

Here are some additional tips to consider when writing your own custom parsers:

+ +

Combining both into one file

+ +

Although parsing requires two classes, you can use the anonymous class feature of PHP to combine both into a single file! Here’s an example:

+ +
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+
+final class MyCustomBlockParser extends AbstractBlockContinueParser
+{
+    // TODO: implement your continuation parsing methods here
+
+    public static function createBlockStartParser(): BlockStartParserInterface
+    {
+        return new class implements BlockStartParserInterface
+        {
+            // TODO: implement the tryStart() method here
+        };
+    }
+}
+
+
+ +

Performance

+ +

The BlockStartParserInterface::tryStart() and BlockContinueParserInterface::tryContinue() methods may be called hundreds or thousands of times during execution. For best performance, have your methods return as early as possible, and make sure your code is highly optimized.

+ +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

If your block contains literal strings/text within the block (and not as part of a child block), you should have your custom block type also implement StringContainerInterface.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/configuration/index.html b/2.3/customization/configuration/index.html new file mode 100644 index 0000000000..abdbf143be --- /dev/null +++ b/2.3/customization/configuration/index.html @@ -0,0 +1,506 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Configuration Schemas and Values

+ +

Version 2.0 introduced a new robust system for defining configuration schemas and accessing them within custom extensions.

+ +

Configuration Schemas

+ +

Unlike in 1.x, all configuration options must have a defined schema. This defines which options are available, what types of values they accept, whether any are required, and any default values you wish to define if the user doesn’t provide any.

+ +

These custom options can be defined from within your custom extension by implementing the ConfigurableExtensionInterface:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+use Nette\Schema\Expect;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        $builder->addSchema('my_extension', Expect::structure([
+            'enable_some_feature' => Expect::bool()->default(true),
+            'html_class' => Expect::string()->default('my-custom-extension'),
+            'align' => Expect::anyOf('left', 'center', 'right')->default('left'),
+            'favorite_number' => Expect::int()->min(1)->max(100)->default(42),
+        ]));
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        // TODO: Implement register() method
+    }
+}
+
+ +

See the league/config documentation for more examples of how to define custom configuration schemas.

+ +

Note that you only need to implement ConfigurableExtensionInterface if you plan to define new configuration options - you don’t need this if you’re only reading existing options.

+ +

Reading Configuration Values

+ +

Okay, so your extension has defined the different options that are available, but now you want to start using them within your custom extension. There are a few ways you can access the values:

+ +

During Extension Registration

+ +

Perhaps your extension needs to decide whether/how to register certain parsers/renderers/etc based on the user-provided configuration values - in that case, you can read the value from the $environment - for example:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        // (see code example above)
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        if ($environment->getConfiguration()->get('my_extension/enable_some_feature')) {
+            $environment->addBlockStartParser(new MyCustomParser());
+            $environment->addRenderer(MyCustomBlockType::class, new MyCustomRenderer());
+        }
+    }
+}
+
+ +

Within Parsers/Renderers/Listeners

+ +

Perhaps you want to reference those configuration values from within a custom parser, renderer, event listener, or something else. This can easily by done by having that class also implement ConfigurationAwareInterface. This interface signals to the Environment that your class needs a copy of the final configuration so it can read it later:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+
+final class MyCustomRenderer implements NodeRendererInterface, ConfigurationAwareInterface
+{
+    /**
+     * @var ConfigurationInterface
+     */
+    private $config;
+
+    public function setConfiguration(ConfigurationInterface $configuration): void
+    {
+        $this->config = $configuration;
+    }
+
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return 'My favorite number is ' . $this->config->get('my_extension/favorite_number');
+    }
+}
+
+ +

You can access any configuration value from here, not just the ones you might have defined yourself.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/cursor/index.html b/2.3/customization/cursor/index.html new file mode 100644 index 0000000000..86e66262a5 --- /dev/null +++ b/2.3/customization/cursor/index.html @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Parser\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter(int $index)Returns the character at the given absolute position
getCurrentCharacter()Returns the character at the current position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/delimiter-processing/index.html b/2.3/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..1d193fb119 --- /dev/null +++ b/2.3/customization/delimiter-processing/index.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis;
+
+// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
use League\CommonMark\Delimiter\Delimiter;
+use League\CommonMark\Node\Inline\Text;
+
+$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/environment/index.html b/2.3/customization/environment/index.html new file mode 100644 index 0000000000..90cf2262a5 --- /dev/null +++ b/2.3/customization/environment/index.html @@ -0,0 +1,504 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all extensions, parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

An empty Environment can be obtained like this:

+ +
use League\CommonMark\Environment\Environment;
+
+$config = [];
+$environment = new Environment($config);
+
+ +

You can customize the Environment using any of the methods below (from the EnvironmentBuilderInterface interface).

+ +

Once your Environment is configured with whatever configuration and extensions you want, you can instantiate a MarkdownConverter and start converting MD to HTML:

+ +
use League\CommonMark\MarkdownConverter;
+
+// Using $environment from the previous code sample
+$converter = new MarkdownConverter($environment);
+
+echo $converter->convert('# Hello World!');
+
+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. For example, if you want core CommonMark functionality plus footnote support:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+$config = [];
+$environment = new Environment($config);
+
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new FootnoteExtension());
+
+ +

addBlockStartParser()

+ +
public function addBlockStartParser(BlockStartParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockStartParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addRenderer()

+ +
public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0);
+
+ +

Registers a NodeRendererInterface to handle a specific type of AST node ($nodeClass) with the given priority (a higher number will be executed earlier).

+ +

See Rendering for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/event-dispatcher/index.html b/2.3/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..772614290b --- /dev/null +++ b/2.3/customization/event-dispatcher/index.html @@ -0,0 +1,578 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Event Dispatcher

+ +

This library includes basic, PSR-14-compliant event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code.

+ +

Event Class

+ +

Any PSR-14 compliant event can be used, though we also provide an AbstractEvent class you can use to easily create your own events:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - the event object to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

League\CommonMark\Event\DocumentPreRenderEvent

+ +

This event is dispatched by the renderer just before rendering begins. Like with DocumentParsedEvent, this offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering, but with the added knowledge of which format is being rendered to (e.g. html).

+ +

League\CommonMark\Event\DocumentRenderedEvent

+ +

This event is dispatched once the rendering step has been completed, just before the output is returned. The final output can be adjusted at this point or additional metadata can be attached to the return object.

+ +

Bring Your Own PSR-14 Event Dispatcher

+ +

Although this library provides PSR-14 compliant event dispatching out-of-the-box, you may want to use your own PSR-14 event dispatcher instead. This is possible as long as that third-party library both:

+ +
    +
  1. Implements the PSR-14 EventDispatcherInterface; and,
  2. +
  3. Allows you to register additional ListenerProviderInterface instances with that dispatcher library
  4. +
+ +

Not all libraries support this so please check carefully! Assuming yours does, delegating all the event behavior to that library can be done with two steps:

+ +

First, call the setEventDispatcher() method on the Environment to register that other implementation. With that done, any calls to Environment::dispatch() will be passed through to that other dispatcher. But we still need to let that dispatcher know about the events registered by CommonMark extensions, otherwise nothing will happen when events are dispatched.

+ +

Because the Environment implements PSR-14’s ListenerProviderInterface you’ll also need to pass the configured Environment object to your event dispatcher so that it becomes aware of those available events.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event): void
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data->append('attributes/class', 'external-link');
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfiguration()->get('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = new Environment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convert($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/extensions/index.html b/2.3/customization/extensions/index.html new file mode 100644 index 0000000000..b09277f809 --- /dev/null +++ b/2.3/customization/extensions/index.html @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a EnvironmentBuilderInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new EmojiExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/inline-parsing/index.html b/2.3/customization/inline-parsing/index.html new file mode 100644 index 0000000000..5c5f40bde7 --- /dev/null +++ b/2.3/customization/inline-parsing/index.html @@ -0,0 +1,596 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getMatchDefinition()

+ +

This method should return an instance of InlineParserMatch which defines the text the parser is looking for. Examples of this might be something like:

+ +
use League\CommonMark\Parser\Inline\InlineParserMatch;
+
+InlineParserMatch::string('@');                  // Match any '@' characters found in the text
+InlineParserMatch::string('foo');                // Match the text 'foo' (case insensitive)
+
+InlineParserMatch::oneOf('@', '!');              // Match either character
+InlineParserMatch::oneOf('http://', 'https://'); // Match either string
+
+InlineParserMatch::regex('\d+');                 // Match the regular expression (omit the regex delimiters and any flags)
+
+ +

Once a match is found, the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has found at a matching string in the current line; and,
  2. +
  3. No other inline parsers with a higher priority have successfully parsed the text at this point in the line
  4. +
+ +

Parameters

+ + + +
InlineParserContext
+ +

This class has several useful methods:

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the text at the current position for any reason. Other parsers will then have a chance to try parsing that text. If all registered parsers return false, the text will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed/matched text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::regex('@([A-Za-z0-9_]{1,15}(?!\w))');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+
+        // This seems to be a valid match
+        // Advance the cursor to the end of the match
+        $cursor->advanceBy($inlineContext->getFullMatchLength());
+
+        // Grab the Twitter handle
+        [$handle] = $inlineContext->getSubMatches();
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+// And here's how to hook it up:
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::oneOf(':)', ':(');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($inlineContext->getFullMatch() === ':)') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($inlineContext->getFullMatch() === ':(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/overview/index.html b/2.3/customization/overview/index.html new file mode 100644 index 0000000000..c6c0dad050 --- /dev/null +++ b/2.3/customization/overview/index.html @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders/configuration you need
  2. +
  3. Instantiate a MarkdownParser and HtmlRenderer using that Environment
  4. +
  5. Use the MarkdownParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  6. +
  7. Use the HtmlRenderer to convert the AST Document into HTML
  8. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+$environment = new Environment([
+    'html_input' => 'strip',
+]);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderDocument($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renderers convert the parsed blocks/inlines from the AST representation into HTML. When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/rendering/index.html b/2.3/customization/rendering/index.html new file mode 100644 index 0000000000..d85dca2787 --- /dev/null +++ b/2.3/customization/rendering/index.html @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Custom Rendering

+ +

Renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement NodeRendererInterface and its render() method. Note that in v2.0, both +block renderers and inline renderers share the same interface and method:

+ +

render()

+ +
public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The HtmlRenderer will call this method during the rendering process whenever a supported element is encountered.

+ +

If your renderer can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the node and its contents, including any children. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\Util\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Renderers

+ +

When registering your renderer, you must tell the Environment which node element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// First param - the node class type that should use our renderer
+// Second param - instance of the renderer
+$environment->addRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple types:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak;
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements NodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(ThematicBreak::class, new TextDividerRenderer());
+
+ +

Note that thematic breaks should not contain children, which is why the $childRenderer is unused in this example. Otherwise we’d have to call code like this and return the result as part of the rendered HTML we’re generating here: $innerHtml = $childRenderer->renderNodes($node->children());

+ +

Tips

+ + + +

Wrapping Elements with HtmlDecorator

+ +

A utility class called HtmlDecorator is provided to make it easier to wrap the output of any renderer within an additional HTML tag with custom attributes and/or classes. To use it:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Renderer\HtmlDecorator;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\Extension\Table\TableRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(Table::class, new HtmlDecorator(new TableRenderer(), 'div', ['class' => 'table-responsive']));
+
+ +

XML Rendering

+ +

The XML renderer will automatically attempt to convert any AST nodes to XML by inspecting the name of the block/inline node and its attributes. You can instead control the XML element name and attributes by making your renderer implement XmlNodeRendererInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+
+class TextDividerRenderer implements NodeRendererInterface, XmlNodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+
+    public function getXmlTagName(Node $node): string
+    {
+        return 'text_divider';
+    }
+
+    public function getXmlAttributes(Node $node): array
+    {
+        return ['character' => '='];
+    }
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/customization/slug-normalizer/index.html b/2.3/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..6f6a50df8e --- /dev/null +++ b/2.3/customization/slug-normalizer/index.html @@ -0,0 +1,505 @@ + + + + + + + + + + + + + + + + + Slug Normalizer - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Slug Normalizer

+ +

“Slugs” are strings used within href, name, and id HTML attributes to identify particular elements within a document.

+ +

Some extensions (like the HeadingPermalinkExtension) need the ability to convert user-provided text into these URL-safe slugs while also ensuring that these are unique throughout the generated HTML. The Environment provides a pre-built normalizer you can use for this purpose.

+ +

Usage

+ +

You can obtain a reference to the built-in slug normalizer by calling $environment->getSlugNormalizer();

+ +

To use this within your extension, have your parser/renderer/whatever implement EnvironmentAwareInterface and then implement the corresponding setEnvironment method like this:

+ +

+use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Environment\EnvironmentAwareInterface;
+
+class MyCustomParserOrRenderer implements EnvironmentAwareInterface
+{
+    private $slugNormalizer;
+
+    public function setEnvironment(EnvironmentInterface $environment): void
+    {
+        $this->slugNormalizer = $environment->getSlugNormalizer();
+    }
+}
+
+ +

You can then call $this->slugNormalizer->normalize($text) as needed.

+ +

Configuration

+ +

The slug_normalizer configuration section allows you to adjust the following options:

+ +

instance

+ +

You can change the string that is used as the “slug” by setting the instance option to any class that implements TextNormalizerInterface. +We provide a simple SlugNormalizer by default, but you may want to plug in a different library or create your own normalizer instead.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

max_length

+ +

This can be configured to limit the length of that slug to prevent overly-long values. By default, that limit is 255 characters. You may set this to any positive integer, or 0 for no limit.

+ +

(Note that generated slugs might be slightly longer than this “limit” if the unique option is enabled and the slug generator detects a duplicate slug and needs to add a suffix to make it unique.)

+ +

unique

+ +

This options controls whether slugs should be unique. Possible values include:

+ + + +

You might have a use case where you’re converting several different Markdown documents on the same page and so you’d like to ensure that none of those documents use conflicting slugs. In that case, you should set the scope option to 'environment' to ensure that a single instance of a MarkdownConverter (which uses a single Environment) will never produce the same slug twice during its lifetime (which usually lasts the entire duration of a single HTTP request).

+ +

If you need complete control over how unique slugs are generated, make your 'instance' implement UniqueSlugNormalizerInterface; otherwise, we’ll simply append incremental numbers to slugs to ensure they are unique.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/attributes/index.html b/2.3/extensions/attributes/index.html new file mode 100644 index 0000000000..c6cac0397d --- /dev/null +++ b/2.3/extensions/attributes/index.html @@ -0,0 +1,486 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+ +

This results in the following output:

+ +
<blockquote title="Blockquote title">
+<p>A nice blockquote</p>
+</blockquote>
+
+ +

CSS-selector-style declarations can be used to set the id and class attributes:

+ +
{#id .class}
+## Header
+
+ +

Output:

+ +
<h2 class="class" id="id">Header</h2>
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Output:

+ +
<p>This is <em style="color: red">red</em>.</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/autolinks/index.html b/2.3/extensions/autolinks/index.html new file mode 100644 index 0000000000..bce037ef6e --- /dev/null +++ b/2.3/extensions/autolinks/index.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a Mention Parser outside of this extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/commonmark/index.html b/2.3/extensions/commonmark/index.html new file mode 100644 index 0000000000..3a465e30e8 --- /dev/null +++ b/2.3/extensions/commonmark/index.html @@ -0,0 +1,454 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically installed for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new Environment with the core extension
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/default-attributes/index.html b/2.3/extensions/default-attributes/index.html new file mode 100644 index 0000000000..d1edfd1484 --- /dev/null +++ b/2.3/extensions/default-attributes/index.html @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + Default Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Default Attributes

+ +

The DefaultAttributesExtension allows you to apply default HTML classes and other attributes using configuration options.

+ +

It works by applying the attributes to the nodes during the DocumentParsedEvent event - right after the nodes are parsed but before they are rendered. +(As a result, it’s possible that renderers may add other attributes - the goal of this extension is only to provide custom defaults.)

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DefaultAttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Node\Block\Paragraph;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'default_attributes' => [
+        Heading::class => [
+            'class' => static function (Heading $node) {
+                if ($node->getLevel() === 1) {
+                    return 'title-main';
+                } else {
+                    return null;
+                }
+            },
+        ],
+        Table::class => [
+            'class' => 'table',
+        ],
+        Paragraph::class => [
+            'class' => ['text-center', 'font-comic-sans'],
+        ],
+        Link::class => [
+            'class' => 'btn btn-link',
+            'target' => '_blank',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new DefaultAttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a default_attributes array. Each key in the array should be a FQCN for the node class you wish to apply the default attribute to, and the values should be a map of attribute names to attribute values.

+ +

Attribute values may be any of the following types:

+ + + +

Examples

+ +

Here’s an example that will apply Bootstrap 4 classes and attributes:

+ +
$config = [
+    'default_attributes' => [
+        Table::class => [
+            'class' => ['table', 'table-responsive'],
+        ],
+        BlockQuote::class => [
+            'class' => 'blockquote',
+        ],
+    ],
+];
+
+ +

Here’s a more complex example that uses a callable to add a class only if the paragraph immediately follows an <h1> heading:

+ +
$config = [
+    'default_attributes' => [
+        Paragraph::class => [
+            'class' => static function (Paragraph $paragraph) {
+                if ($paragraph->previous() instanceof Heading && $paragraph->previous()->getLevel() === 1) {
+                    return 'lead';
+                }
+
+                return null;
+            },
+        ],
+    ],
+];
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/description-lists/index.html b/2.3/extensions/description-lists/index.html new file mode 100644 index 0000000000..2ac3be7f32 --- /dev/null +++ b/2.3/extensions/description-lists/index.html @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + Description List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Description List Extension

+ +

The DescriptionListExtension adds Markdown Extra-style description lists to facilitate the creation of <dl>, <dt>, and <dd> HTML using Markdown.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DescriptionListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\DescriptionList\DescriptionListExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DescriptionListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some markdown goes here');
+
+ +

Syntax

+ +

The syntax is based directly on the rules and logic implemented by the Markdown Extra library. Here are some examples of sample Markdown input and HTML output demonstrating the syntax:

+ +
Apple
+:   Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.
+:   An American computer company.
+
+Orange
+:   The fruit of an evergreen tree of the genus Citrus.
+
+ +
<dl>
+    <dt>Apple</dt>
+    <dd>Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.</dd>
+    <dd>An American computer company.</dd>
+
+    <dt>Orange</dt>
+    <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+
+ +

See the Markdown Extra documentation or our own spec for additional examples.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/disallowed-raw-html/index.html b/2.3/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..37755551e6 --- /dev/null +++ b/2.3/extensions/disallowed-raw-html/index.html @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically escapes certain HTML tags when rendering raw HTML, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Customize the extension's configuration if needed
+// Default values are shown below - you can omit this configuration if you're happy with those defaults
+// and don't want to customize them
+$config = [
+    'disallowed_raw_html' => [
+        'disallowed_tags' => ['title', 'textarea', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'script', 'plaintext'],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I cannot change the page <title>anymore</title>');
+
+ +

Configuration

+ +

This extension can be configured by providing a disallowed_raw_html array with the following nested configuration options. The defaults are shown in the code example above.

+ +

disallowed_tags

+ +

An array containing a list of tags that should be escaped.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/embed/index.html b/2.3/extensions/embed/index.html new file mode 100644 index 0000000000..da42af5aaa --- /dev/null +++ b/2.3/extensions/embed/index.html @@ -0,0 +1,552 @@ + + + + + + + + + + + + + + + + + Embed Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Embed Extension

+ +

This extension can embed rich content (like videos, tweets, etc.) from other websites.

+ +

The syntax is very simple - simply place any https:// URL on its own line like this:

+ +
Check out this video!
+
+https://www.youtube.com/watch?v=dQw4w9WgXcQ
+
+ +

If the link points to embeddable content, it will be replaced with the rich HTML needed to embed it:

+ +
<p>Check out this video:</p>
+<iframe width="200" height="113" src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

You’ll also need to install a third-party OEmbed library - see the Adapter section below.

+ +

Usage

+ +

Configure your Environment as usual and add the EmbedExtension provided by this package:

+ +
use Embed\Embed;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Embed\EmbedExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'embed' => [
+        'adapter' => new OscaroteroEmbedAdapter(), // See the "Adapter" documentation below
+        'allowed_domains' => ['youtube.com', 'twitter.com', 'github.com'],
+        'fallback' => 'link',
+    ],
+];
+
+// Configure the Environment with all whatever other extensions you want
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new EmbedExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
+
+ +

Configuration

+ +

This extension supports the following configuration options under the embed configuration:

+ +

adapter option

+ +

Any instance of EmbedAdapterInterface - see the “Adapter” section below.

+ +

allowed_domains option

+ +

This option defines a list of hosts that you wish to allow embedding content from. For example, setting this to +['youtube.com'] would only allow videos from YouTube to be embedded. +It’s extremely important that you only include websites you trust since they’ll be providing HTML that is directly embedded in your website.

+ +

Any subdomains of these domains will also be allowed. For example, ['youtube.com'] would allow embedding from youtube.com or www.youtube.com.

+ +

As an additional safety measure, we recommend that you also use a Content Security Policy (CSP) +to prevent unexpected content from being embedded.

+ +

By default, this option is an empty array ([]), which means that all domains are allowed.

+ +

fallback option

+ +

This options defines the behavior when a URL cannot be embedded, either because it’s not in the list of allowed_domains, +or because the adapter could not find embeddable content for that URL.

+ +

There are two possible values for this option:

+ + + +

Adapter

+ +

league/commonmark doesn’t know how to obtain the embeddable HTML for a given URL - this must be done by an external library.

+ +

embed/embed Adapter

+ +

We do provide an adapter for the popular embed/embed library. if you’d like to use that. We like this library +because it supports fetching multiple URLs in parallel, which is ideal for performance, and it supports a wide range +of embeddable content.

+ +

To use that library, you’ll need to composer install embed/embed and then pass new OscaroteroEmbedAdapter() as the adapter +configuration option, as shown in the Usage section above.

+ +

Need to customize the maximum width/height of the embedded content? You can do that by instantiating the service provided by +embed/embed, configuring it as needed, and passing that customized instance into the adapter:

+ +
use Embed\Embed;
+use League\CommonMark\Extension\Embed\Bridge\OscaroteroEmbedAdapter;
+
+// Configure the Embed library itself
+$embedLibrary = new Embed();
+$embedLibrary->setSettings([
+    'oembed:query_parameters' => [
+        'maxwidth' => 800,
+        'maxheight' => 600,
+    ],
+    'twitch:parent' => 'example.com',
+    'facebook:token' => '1234|5678',
+    'instagram:token' => '1234|5678',
+    'twitter:token' => 'asdf',
+]);
+
+// Inject it into our adapter
+$config = [
+    'adapter' => new OscaroteroEmbedAdapter($embedLibrary),
+];
+
+// Instantiate your CommonMark environment and converter like usual
+// ...
+
+ +

Custom Adapter

+ +

If you prefer to use a different library, you’ll need to implement our EmbedAdapterInterface yourself with +whatever OEmbed library you choose.

+ +

Tips

+ +

If you need to wrap the HTML in a container tag, consider using the HtmlDecorator renderer:

+ +
$environment->addRenderer(Embed::class, new HtmlDecorator(new EmbedRenderer(), 'div', ['class' => 'embeded-content']));
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/external-links/index.html b/2.3/extensions/external-links/index.html new file mode 100644 index 0000000000..fe49a3299f --- /dev/null +++ b/2.3/extensions/external-links/index.html @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class MyCustomLinkRenderer implements NodeRendererInterface
+{
+    /**
+     * @param Node                       $node
+     * @param ChildNodeRendererInterface $childRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        if (!($node instanceof Link)) {
+            throw new \InvalidArgumentException('Incompatible node type: ' . \get_class($node));
+        }
+
+        if ($node->data->get('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/footnotes/index.html b/2.3/extensions/footnotes/index.html new file mode 100644 index 0000000000..46a4e818cb --- /dev/null +++ b/2.3/extensions/footnotes/index.html @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1"></a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'backref_symbol'     => '↩',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

backref_symbol

+ +

This string option sets the symbol used as the contents of the footnote backreference link. It defaults to \League\CommonMark\Extension\Footnote\Renderer\FootnoteBackrefRenderer::DEFAULT_SYMBOL = '↩'.

+ +

If you want to use a custom icon, set this to an empty string '' and take a look at the Adding Icons section below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ +

Adding Icons

+ +

You can use CSS to add a custom icon instead of providing a backref_symbol:

+ +
$config = [
+    'footnote' => [
+        'backref_class' => 'footnote-backref',
+        'backref_symbol' => '',
+    ],
+];
+
+ +

Then target the backref_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.footnote-backref::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/front-matter/index.html b/2.3/extensions/front-matter/index.html new file mode 100644 index 0000000000..76706516fd --- /dev/null +++ b/2.3/extensions/front-matter/index.html @@ -0,0 +1,546 @@ + + + + + + + + + + + + + + + + + Front Matter Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Front Matter Extension

+ +

The FrontMatterExtension adds the ability to parse YAML front matter from the Markdown document and include that in the return result.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

You will also need to install symfony/yaml or the YAML extension for PHP to use this extension. For symfony/yaml:

+ +
composer require symfony/yaml
+
+ +

(You can use any version of symfony/yaml 2.3 or higher, though we recommend using 4.0 or higher.)

+ +

Front Matter Syntax

+ +

This extension follows the Jekyll Front Matter syntax. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:

+ +
---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+
+ +

This will produce a front matter array similar to this:

+ +
$parsedFrontMatter = [
+    'layout' => 'post',
+    'title' => 'I Love Markdown',
+    'tags' => [
+        'test',
+        'example',
+    ],
+];
+
+ +

And the HTML output will only contain the one heading:

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

Usage

+ +

Configure your Environment as usual and add the FrontMatterExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FrontMatterExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+// A sample Markdown file with some front matter:
+$markdown = <<<MD
+---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+MD;
+
+$result = $converter->convert($markdown);
+
+// Grab the front matter:
+if ($result instanceof RenderedContentWithFrontMatter) {
+    $frontMatter = $result->getFrontMatter();
+}
+
+// Output the HTML using any of these:
+echo $result;               // implicit string cast
+// or:
+echo (string) $result;      // explicit string cast
+// or:
+echo $result->getContent();
+
+ +

Parsing Front Matter Only

+ +

You don’t have to parse the entire file (including all the Markdown) if you only want the front matter. You can either instantiate the front matter parser yourself and call it directly, like this:

+ +
use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+// For `symfony/yaml`
+$frontMatterParser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
+// For YAML extension
+$frontMatterParser = new FrontMatterParser(new LibYamlFrontMatterParser());
+$result = $frontMatterParser->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

Or you can use the getFrontMatterParser() method from the extension:

+ +
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+$frontMatterExtension = new FrontMatterExtension();
+$result = $frontMatterExtension->getFrontMatterParser()->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

This latter approach may be more convenient if you have already instantiated a FrontMatterExtension object you’re adding to the Environment somewhere and just want to call that.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/github-flavored-markdown/index.html b/2.3/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..765ac22e5a --- /dev/null +++ b/2.3/extensions/github-flavored-markdown/index.html @@ -0,0 +1,471 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark and GFM parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/heading-permalinks/index.html b/2.3/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..a98020e76b --- /dev/null +++ b/2.3/extensions/heading-permalinks/index.html @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'content',
+        'fragment_prefix' => 'content',
+        'insert' => 'before',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'aria_hidden' => true,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

fragment_prefix

+ +

This should be a string you want prepended to the URL fragment in the link’s href attribute. This should typically be set to the same value as id_prefix for links to work properly. However, you may not want to expose that same prefix in your URLs - in that case, you can set this to something different (even an empty string) and use JavaScript to “rewrite” them.

+ +

For example, to emulate how GitHub heading permalinks work, set id_prefix to 'user-content', set fragment_prefix to '', and insert some JavaScript into the page like this:

+ +
var scrollToPermalink = function() {
+    var link = document.getElementById('user-content-' + window.location.hash);
+    if (link) {
+        link.scrollIntoView({behavior: 'smooth'});
+    }
+};
+
+window.addEventListener('hashchange', scrollToPermalink);
+if (window.location.hash) {
+    scrollToPermalink();
+}
+
+ +

insert

+ +

This controls whether the anchor is added to the beginning of the <h1>, <h2> etc. tag or to the end. Can be set to either 'before' or 'after'.

+ +

min_heading_level and max_heading_level

+ +

These two settings control which headings should have permalinks added. By default, all 6 levels (1, 2, 3, 4, 5, and 6) will have them. You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

aria_hidden

+ +

This option sets the aria-hidden attribute on the <a> tag. This defaults to aria-hidden="true".

+ +

Setting this option to false would render the <a> tag excluding the aria-hidden entirely.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/inlines-only/index.html b/2.3/extensions/inlines-only/index.html new file mode 100644 index 0000000000..7933812cb6 --- /dev/null +++ b/2.3/extensions/inlines-only/index.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new, empty environment
+$environment = new Environment($config);
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/mentions/index.html b/2.3/extensions/mentions/index.html new file mode 100644 index 0000000000..0f38f9f58f --- /dev/null +++ b/2.3/extensions/mentions/index.html @@ -0,0 +1,670 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting prefix, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the first mention parser to
+        // successfully match and return a properly constructed Mention object (where the URL has been set) will be the
+        // the mention parser that is used. In this example, the GitHub handle would actually match first because
+        // there isn't any real validation to check whether https://www.github.com/colinodell exists. However, in
+        // CMS applications, you could check whether its a local user first, then check Twitter and then GitHub, etc.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on GitHub: @colinodell');
+// Output:
+// <p>Follow me on GitHub: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regular expression pattern (without opening/closing delimiter or modifiers), or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Inline\Element\AbstractInline;
+
+class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/overview/index.html b/2.3/extensions/overview/index.html new file mode 100644 index 0000000000..623e7ec505 --- /dev/null +++ b/2.3/extensions/overview/index.html @@ -0,0 +1,602 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Default AttributesEasily apply default HTML classes using configuration options to match your site’s styles2.0.0 
Description ListsCreate <dl> description lists using Markdown Extra’s syntax2.0.0 
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
EmbedEmbed rich content (like videos, tweets, and more) from other websites2.3.0 
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
Front MatterParses YAML front matter from your Markdown input2.0.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the extensions you need
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the other extensions you need
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/smart-punctuation/index.html b/2.3/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..6a10c05aa4 --- /dev/null +++ b/2.3/extensions/smart-punctuation/index.html @@ -0,0 +1,463 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/strikethrough/index.html b/2.3/extensions/strikethrough/index.html new file mode 100644 index 0000000000..9b64b2cede --- /dev/null +++ b/2.3/extensions/strikethrough/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/table-of-contents/index.html b/2.3/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..be25e71558 --- /dev/null +++ b/2.3/extensions/table-of-contents/index.html @@ -0,0 +1,601 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
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;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/tables/index.html b/2.3/extensions/tables/index.html new file mode 100644 index 0000000000..c3014f3ee9 --- /dev/null +++ b/2.3/extensions/tables/index.html @@ -0,0 +1,526 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => false,
+            'tag' => 'div',
+            'attributes' => [],
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Configuration

+ +

Wrapping Container

+ +

You can “wrap” the table with a container element by configuring the following options:

+ + + +

For example, to wrap all tables within a <div class="table-responsive"> container element:

+ +
$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => true,
+            'tag' => 'div',
+            'attributes' => ['class' => 'table-responsive'],
+        ],
+    ],
+];
+
+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/extensions/task-lists/index.html b/2.3/extensions/task-lists/index.html new file mode 100644 index 0000000000..6978a66764 --- /dev/null +++ b/2.3/extensions/task-lists/index.html @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convert($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/index.html b/2.3/index.html new file mode 100644 index 0000000000..b5dc052357 --- /dev/null +++ b/2.3/index.html @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello, World!')->getContent();
+
+// <h1>Hello, World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/installation/index.html b/2.3/installation/index.html new file mode 100644 index 0000000000..ef8258cf20 --- /dev/null +++ b/2.3/installation/index.html @@ -0,0 +1,422 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Installation

+ +

The recommended installation method is via Composer.

+ +
composer require "league/commonmark:^2.3"
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^2.3. This is equivalent to >=2.3 <3.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/security/index.html b/2.3/security/index.html new file mode 100644 index 0000000000..feb1449730 --- /dev/null +++ b/2.3/security/index.html @@ -0,0 +1,497 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convert($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like html-sanitizer). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/support/index.html b/2.3/support/index.html new file mode 100644 index 0000000000..5012a9e5dc --- /dev/null +++ b/2.3/support/index.html @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/upgrading/index.html b/2.3/upgrading/index.html new file mode 100644 index 0000000000..b48f268be4 --- /dev/null +++ b/2.3/upgrading/index.html @@ -0,0 +1,415 @@ + + + + + + + + + + + + + + + + + Upgrading from 2.2 to 2.3 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

Upgrading from 2.2 to 2.3

+ +

Avoid deprecated interface

+ +

MarkdownRendererInterface has been deprecated and will be removed in the next major version. Please use DocumentRendererInterface instead.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.3/xml/index.html b/2.3/xml/index.html new file mode 100644 index 0000000000..565f0d76b0 --- /dev/null +++ b/2.3/xml/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + XML Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + +

This is the documentation for the unsupported version 2.3. Please consider upgrading your code to the latest stable version

+ + +

XML Rendering

+ +

Version 2.0 introduced the ability to render Markdown Document objects in XML. This is particularly useful for debugging custom extensions as you can see the XML representation of the Abstract Syntax Tree.

+ +

To convert Markdown to XML, you would instantiate a MarkdownToXmlConverter with an Environment and then call convert() on any Markdown.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Xml\MarkdownToXmlConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$converter = new MarkdownToXmlConverter($environment);
+
+echo $converter->convert('# **Hello** World!');
+
+ +

This will display XML output like this:

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<document xmlns="http://commonmark.org/xml/1.0">
+    <heading level="1">
+        <strong>
+            <text>Hello</text>
+        </strong>
+        <text> World!</text>
+    </heading>
+</document>
+
+ +

Alternatively, if you already have a Document object you want to visualize in XML, you can use theXmlRenderer class to convert it to XML.

+ +

Return Value

+ +

Like with CommonMarkConverter::convert(), the renderDocument() actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final XML output.

+ +

Customizing the XML Output

+ +

See the rendering documentation for information on customizing the XML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/basic-usage/index.html b/2.4/basic-usage/index.html new file mode 100644 index 0000000000..f86a36d91c --- /dev/null +++ b/2.4/basic-usage/index.html @@ -0,0 +1,504 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Basic Usage

+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Using Extensions

+ +

The CommonMarkConverter and GithubFlavoredMarkdownConverter shown above automatically configure the environment for you, but if you want to use additional extensions you’ll need to avoid those classes and use the generic MarkdownConverter class instead to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

Configuration

+ +

If you’re using the CommonMarkConverter or GithubFlavoredMarkdownConverter class you can pass configuration options directly into their constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

See the configuration section for more information on the available configuration options.

+ +

Supported Character Encodings

+ +

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.

+ +

Return Value

+ +

The convert() method actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final HTML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/changelog/index.html b/2.4/changelog/index.html new file mode 100644 index 0000000000..584ba72a86 --- /dev/null +++ b/2.4/changelog/index.html @@ -0,0 +1,627 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Changelog

+ +

All notable changes made in 2.x releases are shown below. See the full list of releases for the complete changelog.

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

2.4.4 - 2024-07-22

+ +

Fixed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

+ +

2.4.3 - 2024-07-22

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.2…2.4.3

+ +

2.4.2 - 2024-02-02

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.1…2.4.2

+ +

2.4.1 - 2023-08-30

+ +

Fixed

+ + + +

2.4.0 - 2023-03-24

+ +

See the upgrading guide for more information about the exception-related changes

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/configuration/index.html b/2.4/configuration/index.html new file mode 100644 index 0000000000..78f8693820 --- /dev/null +++ b/2.4/configuration/index.html @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the Environment or converter classes when creating them:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+    'slug_normalizer' => [
+        'max_length' => 255,
+    ],
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of the core configuration options available:

+ + + +

Additional configuration options are available for most of the available extensions - refer to their individual documentation for more details. For example, the CommonMark core extension offers these additional options:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/abstract-syntax-tree/index.html b/2.4/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..b459d66ab5 --- /dev/null +++ b/2.4/customization/abstract-syntax-tree/index.html @@ -0,0 +1,710 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Visualization

+ +

Even with an interactive debugger it can be tricky to view an entire tree at once. Consider using the XmlRenderer to provide a simple text-based representation of the AST for debugging purposes.

+ +

Node Traversal

+ +

There are four different ways to traverse/iterate the Nodes within the AST:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodProsCons
Manual TraversalBest way to access/check direct relatives of nodesNot useful for iteration
Iterating the TreeFast and efficientPossible unexpected behavior when adding/removing sibling nodes while iterating
Walking the TreeFull control over iterationUp to twice as slow as iteration; adding/removing nodes while iterating can lead to weird behaviors
Querying NodesEasier to write and understand; no weird behaviorsNot memory efficient
+ +

Each is described in more detail below

+ +

Manual Traversal

+ +

The following methods can be used to manually traverse from one Node to any of its direct relatives:

+ + + +

This is best suited for situations when you need to know information about those relatives.

+ +

Iterating the Tree

+ +

If you’d like to iterate through all the nodes, use the iterator() method to obtain an iterator that will loop through each node in the tree (using pre-order traversal):

+ +
foreach ($document->iterator() as $node) {
+    echo 'Current node: ' . get_class($node) . "\n";
+}
+
+ +

Given an AST like this (XML representation):

+ +
<document>
+  <heading level="1">
+    <text>Hello World!</text>
+  </heading>
+  <paragraph>
+    <text>This is an example of </text>
+    <strong>
+      <text>CommonMark</text>
+    </strong>
+    <text>.</text>
+  </paragraph>
+</document>
+
+ +

The code above will output:

+ +
Current node: League\CommonMark\Node\Block\Document
+Current node: League\CommonMark\Extension\CommonMark\Node\Block\Heading
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Block\Paragraph
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Extension\CommonMark\Node\Inline\Strong
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Inline\Text
+
+ +

This iterator doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes. It’s also very CPU and memory-efficient.

+ +

Be careful when modifying nodes while iterating the tree as some of those changes may affect the current iteration process, especially for sibling nodes that come after the current one. For example, if you remove the current node’s next() sibling, the next loop of that iteration will still include the removed sibling even though it was successfully removed from the AST. Similarly, any new siblings that are added won’t be visited on the next loop.

+ +

Walking the Tree

+ +

If you’d like to walk through all the nodes, visiting each one as you enter and leave it, use the walker() method to obtain an instance of NodeWalker. This also uses pre-order traversal but emitting NodeWalkerEvents along the way:

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'Now ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

Using the same example AST in the previous section, this code will output:

+ +
Now entering a League\CommonMark\Node\Block\Document node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Block\Paragraph node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Node\Block\Paragraph node
+Now leaving a League\CommonMark\Node\Block\Document node
+
+ +

This approach offers many of the same benefits as the simple iteration shown in the previous section such as memory efficiency and no recursion. The key differences come from how you enter and leave nodes:

+ +
    +
  1. Iteration can potentially take twice as long - not ideal for performance
  2. +
  3. Provides you with more control over exactly when an action is taken on a node which is sometimes needed for certain AST manipulations
  4. +
  5. Also provides a resumeAt() method to override where it should iterate next
  6. +
+ +

But like with the iterator, be careful when adding/removing nodes while walking the tree, as there are even more subtle cases where the walker could even lose track of where it was, which may result in some nodes being visited multiple times or not at all.

+ +

Querying Nodes

+ +

If you’re trying to locate certain nodes to perform actions on them, querying the nodes from the AST might be easier to implement. This can be done with the Query class:

+ +
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Query;
+
+// Find all paragraphs and blockquotes that contain links
+$matchingNodes = (new Query())
+    ->where(Query::type(Paragraph::class))
+    ->orWhere(Query::type(BlockQuote::class))
+    ->andWhere(Query::hasChild(Query::type(Link::class)))
+    ->findAll($document);
+
+foreach ($matchingNodes as $node) {
+    // TODO: Do something with them
+}
+
+ +

Each condition passed into where(), orWhere(), or andWhere() must be a callable “filter” that accepts a Node and returns true or false. We provide several methods that can help create these filters for you:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Query::type(string $class)Creates a filter that matches nodes with the given class name
Query::hasChild()Creates a filter that matches nodes which contain at least one child
Query::hasChild(callable $condition)Creates a filter that matches nodes which contain at least one child that matches the inner $condition
Query::hasParent()Creates a filter that matches nodes which have a parent
Query::hasParent(callable $condition)Creates a filter that matches nodes which have a parent that matches the inner $condition
+ +

You can of course create your own custom filters/conditions using an anonymous function or by implementing ExpressionInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Node\Query;
+use League\CommonMark\Node\Query\ExpressionInterface;
+
+class ChildCountGreaterThan implements ExpressionInterface
+{
+    private $count;
+
+    public function __construct(int $count)
+    {
+        $this->count = $count;
+    }
+
+    public function __invoke(Node $node) : bool{
+        return count($node->children()) > $this->count;
+    }
+}
+
+$query = (new Query())
+    ->where(function (Node $node): bool { return $node->data->has('attributes/class'); })
+    ->andWhere(new ChildCountGreaterThan(3));
+
+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ +

Data Storage

+ +

Each Node has a property called data which is a Data (array-like) object. This can be used to store any arbitrary data you’d like on the node:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text1 = new Text('Hello, world!');
+$text1->data->set('language', 'English');
+$text1->data->set('is_good_translation', true);
+
+$text2 = new Text('Bonjour monde!');
+$text2->data->set('language', 'French');
+$text2->data->set('is_good_translation', false);
+
+foreach ([$text1, $text2] as $text) {
+    if ($text->data->get('is_good_translation')) {
+        sprintf('In %s we would say: "%s"', $text->data->get('language'), $text->getLiteral());
+    } else {
+        sprintf('I think they would say "%s" in %s, but I\'m not sure.', $text->getLiteral(), $text->data->get('language'));
+    }
+}
+
+ +

You can also access deeply-nested paths using / or . as delimiters:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text = new Text('Hello, world!');
+$text->data->set('info', ['language' => 'English', 'is_good_translation' => true]);
+
+var_dump($text->data->get('info/language'));
+var_dump($text->data->get('info.is_good_translation'));
+
+$text->data->set('info/is_example', true);
+
+ +

HTML Attributes

+ +

The data property comes pre-instantiated with a single data element called attributes which is used to store any HTML attributes that need to be rendered. For example:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+$link = new Link('https://twitter.com/colinodell', '@colinodell');
+$link->data->append('attributes/class', 'social-link');
+$link->data->append('attributes/class', 'twitter');
+$link->data->set('attributes/target', '_blank');
+$link->data->set('attributes/rel', 'noopener');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/block-parsing/index.html b/2.4/customization/block-parsing/index.html new file mode 100644 index 0000000000..954358bf36 --- /dev/null +++ b/2.4/customization/block-parsing/index.html @@ -0,0 +1,554 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Block Parsing

+ +

At a high level, block parsing is a two-step process:

+ +
    +
  1. Using a BlockStartParserInterface to identify if/where a block start exists on the given line
  2. +
  3. Using a BlockContinueParserInterface to perform additional processing of the identified block
  4. +
+ +

So to implement a custom block parser you will actually need to implement both of these classes.

+ +

BlockStartParserInterface

+ +

Instances of this interface have a single tryStart() method:

+ +
/**
+ * Check whether we should handle the block at the current position
+ *
+ * @param Cursor                       $cursor
+ * @param MarkdownParserStateInterface $parserState
+ *
+ * @return BlockStart|null
+ */
+public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart;
+
+ +

Given a Cursor at the current position, plus some extra information about the state of the parser, this method is responsible for determining whether a particular type of block seems to exist at the given position. You don’t actually parse the block here - that’s the job of a BlockContinueParserInterface. Your only job here is to return whether or not a particular type of block does exist here, and if so which block parser should parse it.

+ +

If you find that you cannot parse the given block, you should return BlockStart::none(); from this function.

+ +

However, if the Markdown at the current position does indeed seem to be the type of block you’re looking for, you should return a BlockStart instance using the following static constructor pattern:

+ +
use League\CommonMark\Parser\Block\BlockStart;
+
+return BlockStart::of(new MyCustomParser())->at($cursor);
+
+ +

Unlike in 1.x, the Cursor state is no longer shared between parsers. You must therefore explicitly provide the BlockStart object with a copy of your cursor at the correct, post-parsing position.

+ +

NOTE: If your custom block starts with a letter character you’ll need to add your parser to the environment with a priority of 250 or higher. This is due to a performance optimization where such lines are usually skipped.

+ +

BlockContinueParserInterface

+ +

The previous interface only helps the engine identify where a block starts. Additional information about the block, as well as the ability to parse additional lines of input, is all handled by the BlockContinueParserInterface.

+ +

This interface has several methods, so it’s usually easier to extend from AbstractBlockContinueParser instead, which sets most of the methods to use typical defaults you can override as needed.

+ +

getBlock()

+ +
public function getBlock(): AbstractBlock;
+
+ +

Each instance of a BlockContinueParserInterface is associated with a new block that is being parsed. This method here returns that block.

+ +

isContainer()

+ +
public function isContainer(): bool;
+
+ +

This method returns whether or not the block is a “container” capable of containing other blocks as children.

+ +

canContain()

+ +
public function canContain(AbstractBlock $childBlock): bool;
+
+ +

This method returns whether the current block being parsed can contain the given child block.

+ +

canHaveLazyContinuationLines()

+ +
public function canHaveLazyContinuationLines(): bool;
+
+ +

This method returns whether or not this parser should also receive subsequent lines of Markdown input. This is primarily used when a block can span multiple lines, like code blocks do.

+ +

addLine()

+ +
public function addLine(string $line): void;
+
+ +

If canHaveLazyContinuationLines() returned true, this method will be called with the additional lines of content.

+ +

tryContinue()

+ +
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue;
+
+ +

This method allows you to try and parse an additional line of Markdown.

+ +

closeBlock()

+ +
public function closeBlock(): void;
+
+ +

This method is called when the block is done being parsed. Any final adjustments to the block should be made at this time.

+ +

parseInlines()

+ +
public function parseInlines(InlineParserEngineInterface $inlineParser): void;
+
+ +

This method is called when the engine is ready to parse any inline child elements.

+ +

Note: For performance reasons, this method is not part of BlockContinueParserInterface. If your block may contain inlines, you should make sure that your “continue parser” also implements BlockContinueParserWithInlinesInterface.

+ +

Tips

+ +

Here are some additional tips to consider when writing your own custom parsers:

+ +

Combining both into one file

+ +

Although parsing requires two classes, you can use the anonymous class feature of PHP to combine both into a single file! Here’s an example:

+ +
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+
+final class MyCustomBlockParser extends AbstractBlockContinueParser
+{
+    // TODO: implement your continuation parsing methods here
+
+    public static function createBlockStartParser(): BlockStartParserInterface
+    {
+        return new class implements BlockStartParserInterface
+        {
+            // TODO: implement the tryStart() method here
+        };
+    }
+}
+
+
+ +

Performance

+ +

The BlockStartParserInterface::tryStart() and BlockContinueParserInterface::tryContinue() methods may be called hundreds or thousands of times during execution. For best performance, have your methods return as early as possible, and make sure your code is highly optimized.

+ +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

If your block contains literal strings/text within the block (and not as part of a child block), you should have your custom block type also implement StringContainerInterface.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/configuration/index.html b/2.4/customization/configuration/index.html new file mode 100644 index 0000000000..6c029db2ea --- /dev/null +++ b/2.4/customization/configuration/index.html @@ -0,0 +1,510 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Configuration Schemas and Values

+ +

Version 2.0 introduced a new robust system for defining configuration schemas and accessing them within custom extensions.

+ +

Configuration Schemas

+ +

Unlike in 1.x, all configuration options must have a defined schema. This defines which options are available, what types of values they accept, whether any are required, and any default values you wish to define if the user doesn’t provide any.

+ +

These custom options can be defined from within your custom extension by implementing the ConfigurableExtensionInterface:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+use Nette\Schema\Expect;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        $builder->addSchema('my_extension', Expect::structure([
+            'enable_some_feature' => Expect::bool()->default(true),
+            'html_class' => Expect::string()->default('my-custom-extension'),
+            'align' => Expect::anyOf('left', 'center', 'right')->default('left'),
+            'favorite_number' => Expect::int()->min(1)->max(100)->default(42),
+        ]));
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        // TODO: Implement register() method
+    }
+}
+
+ +

See the league/config documentation for more examples of how to define custom configuration schemas.

+ +

Note that you only need to implement ConfigurableExtensionInterface if you plan to define new configuration options - you don’t need this if you’re only reading existing options.

+ +

Reading Configuration Values

+ +

Okay, so your extension has defined the different options that are available, but now you want to start using them within your custom extension. There are a few ways you can access the values:

+ +

During Extension Registration

+ +

Perhaps your extension needs to decide whether/how to register certain parsers/renderers/etc based on the user-provided configuration values - in that case, you can read the value from the $environment - for example:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        // (see code example above)
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        if ($environment->getConfiguration()->get('my_extension/enable_some_feature')) {
+            $environment->addBlockStartParser(new MyCustomParser());
+            $environment->addRenderer(MyCustomBlockType::class, new MyCustomRenderer());
+        }
+    }
+}
+
+ +

Within Parsers/Renderers/Listeners

+ +

Perhaps you want to reference those configuration values from within a custom parser, renderer, event listener, or something else. This can easily by done by having that class also implement ConfigurationAwareInterface. This interface signals to the Environment that your class needs a copy of the final configuration so it can read it later:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+
+final class MyCustomRenderer implements NodeRendererInterface, ConfigurationAwareInterface
+{
+    /**
+     * @var ConfigurationInterface
+     */
+    private $config;
+
+    public function setConfiguration(ConfigurationInterface $configuration): void
+    {
+        $this->config = $configuration;
+    }
+
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return 'My favorite number is ' . $this->config->get('my_extension/favorite_number');
+    }
+}
+
+ +

You can access any configuration value from here, not just the ones you might have defined yourself.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/cursor/index.html b/2.4/customization/cursor/index.html new file mode 100644 index 0000000000..d118dfe48d --- /dev/null +++ b/2.4/customization/cursor/index.html @@ -0,0 +1,547 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Parser\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter(int $index)Returns the character at the given absolute position
getCurrentCharacter()Returns the character at the current position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/delimiter-processing/index.html b/2.4/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..dfee97ee27 --- /dev/null +++ b/2.4/customization/delimiter-processing/index.html @@ -0,0 +1,506 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis;
+
+// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
use League\CommonMark\Delimiter\Delimiter;
+use League\CommonMark\Node\Inline\Text;
+
+$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/disabling-features/index.html b/2.4/customization/disabling-features/index.html new file mode 100644 index 0000000000..f0f3b93b92 --- /dev/null +++ b/2.4/customization/disabling-features/index.html @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + Disabling Features - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Disabling Features

+ +

The CommonMark parser is designed to be highly configurable. You can disable certain features that you don’t want to have in your application. There are a few ways to do this, depending on your needs:

+ +

Avoiding Parsing

+ +

You cannot disable an already-registered parser, but you can prevent it from being registered with +the Environment in the first place. This is exactly how the +InlinesOnlyExtension works - it’s a copy of the CommonMarkCoreExtension class but +with the parsers we don’t want removed.

+ +

You can mirror this approach by defining your own custom extension class that registers +only the specific parsers, renderers, etc. that you want.

+ +

The only potential downside to this approach is that any syntax for those disabled features will appear in the output. +For example, if you were to prevent block quotes from being parsed, then the following Markdown:

+ +
> This is a block quote
+
+ +

Would have the > character appear in the output HTML:

+ +
<p>&gt; This is a block quote</p>
+
+ +

This is probably fine for most use cases.

+ +

Removing Parsed Elements

+ +

An alternative approach is to keep the parser enabled, but remove the parsed elements from the AST before rendering.

+ +

You’d create an event listener +(sort of like this one) that will +iterate all parsed elements, locate the target nodes, and remove them +by calling $node->detach().

+ +

There are three potential advantages to this approach:

+ +
    +
  1. You don’t need to create a custom extension class or prevent parsers from being registered
  2. +
  3. You can selectively remove certain elements based on their properties (e.g. only remove heading levels 3-6) while keeping others
  4. +
  5. The syntax and contents of the removed elements will not appear in the output HTML
  6. +
+ +

The downside is that you still incur the overhead of parsing the elements that are eventually removed.

+ +

Override Rendering

+ +

The final approach is to keep the parser enabled, but override how the parsed elements are rendered. For example, +you could implement a custom renderer for certain elements that simply returns +something else (perhaps an empty string, or an HTML comment of <!-- REMOVED -->) instead of the HTML you don’t want.

+ +

This approach is not recommended because:

+ +
    +
  1. You still incur the overhead of parsing the elements that are eventually removed
  2. +
  3. You’d need to register your custom renderer with a higher priority than the default renderer
  4. +
  5. You’d need to repeat this for every renderer that could potentially render the elements you want to remove
  6. +
+ +

It should technically work though, if you really want to go this route.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/environment/index.html b/2.4/customization/environment/index.html new file mode 100644 index 0000000000..d90eacf996 --- /dev/null +++ b/2.4/customization/environment/index.html @@ -0,0 +1,508 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all extensions, parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

An empty Environment can be obtained like this:

+ +
use League\CommonMark\Environment\Environment;
+
+$config = [];
+$environment = new Environment($config);
+
+ +

You can customize the Environment using any of the methods below (from the EnvironmentBuilderInterface interface).

+ +

Once your Environment is configured with whatever configuration and extensions you want, you can instantiate a MarkdownConverter and start converting MD to HTML:

+ +
use League\CommonMark\MarkdownConverter;
+
+// Using $environment from the previous code sample
+$converter = new MarkdownConverter($environment);
+
+echo $converter->convert('# Hello World!');
+
+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. For example, if you want core CommonMark functionality plus footnote support:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+$config = [];
+$environment = new Environment($config);
+
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new FootnoteExtension());
+
+ +

addBlockStartParser()

+ +
public function addBlockStartParser(BlockStartParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockStartParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addRenderer()

+ +
public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0);
+
+ +

Registers a NodeRendererInterface to handle a specific type of AST node ($nodeClass) with the given priority (a higher number will be executed earlier).

+ +

See Rendering for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/event-dispatcher/index.html b/2.4/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..2affccd0a3 --- /dev/null +++ b/2.4/customization/event-dispatcher/index.html @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Event Dispatcher

+ +

This library includes basic, PSR-14-compliant event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code.

+ +

Event Class

+ +

Any PSR-14 compliant event can be used, though we also provide an AbstractEvent class you can use to easily create your own events:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - the event object to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

League\CommonMark\Event\DocumentPreRenderEvent

+ +

This event is dispatched by the renderer just before rendering begins. Like with DocumentParsedEvent, this offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering, but with the added knowledge of which format is being rendered to (e.g. html).

+ +

League\CommonMark\Event\DocumentRenderedEvent

+ +

This event is dispatched once the rendering step has been completed, just before the output is returned. The final output can be adjusted at this point or additional metadata can be attached to the return object.

+ +

Bring Your Own PSR-14 Event Dispatcher

+ +

Although this library provides PSR-14 compliant event dispatching out-of-the-box, you may want to use your own PSR-14 event dispatcher instead. This is possible as long as that third-party library both:

+ +
    +
  1. Implements the PSR-14 EventDispatcherInterface; and,
  2. +
  3. Allows you to register additional ListenerProviderInterface instances with that dispatcher library
  4. +
+ +

Not all libraries support this so please check carefully! Assuming yours does, delegating all the event behavior to that library can be done with two steps:

+ +

First, call the setEventDispatcher() method on the Environment to register that other implementation. With that done, any calls to Environment::dispatch() will be passed through to that other dispatcher. But we still need to let that dispatcher know about the events registered by CommonMark extensions, otherwise nothing will happen when events are dispatched.

+ +

Because the Environment implements PSR-14’s ListenerProviderInterface you’ll also need to pass the configured Environment object to your event dispatcher so that it becomes aware of those available events.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event): void
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data->append('attributes/class', 'external-link');
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfiguration()->get('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = new Environment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convert($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/extensions/index.html b/2.4/customization/extensions/index.html new file mode 100644 index 0000000000..1f5f80883e --- /dev/null +++ b/2.4/customization/extensions/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Environment\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment): void
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new EmojiExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/inline-parsing/index.html b/2.4/customization/inline-parsing/index.html new file mode 100644 index 0000000000..405bb47fd1 --- /dev/null +++ b/2.4/customization/inline-parsing/index.html @@ -0,0 +1,600 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getMatchDefinition()

+ +

This method should return an instance of InlineParserMatch which defines the text the parser is looking for. Examples of this might be something like:

+ +
use League\CommonMark\Parser\Inline\InlineParserMatch;
+
+InlineParserMatch::string('@');                  // Match any '@' characters found in the text
+InlineParserMatch::string('foo');                // Match the text 'foo' (case insensitive)
+
+InlineParserMatch::oneOf('@', '!');              // Match either character
+InlineParserMatch::oneOf('http://', 'https://'); // Match either string
+
+InlineParserMatch::regex('\d+');                 // Match the regular expression (omit the regex delimiters and any flags)
+
+ +

Once a match is found, the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has found at a matching string in the current line; and,
  2. +
  3. No other inline parsers with a higher priority have successfully parsed the text at this point in the line
  4. +
+ +

Parameters

+ + + +
InlineParserContext
+ +

This class has several useful methods:

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the text at the current position for any reason. Other parsers will then have a chance to try parsing that text. If all registered parsers return false, the text will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed/matched text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::regex('@([A-Za-z0-9_]{1,15}(?!\w))');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+
+        // This seems to be a valid match
+        // Advance the cursor to the end of the match
+        $cursor->advanceBy($inlineContext->getFullMatchLength());
+
+        // Grab the Twitter handle
+        [$handle] = $inlineContext->getSubMatches();
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+// And here's how to hook it up:
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::oneOf(':)', ':(');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($inlineContext->getFullMatch() === ':)') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($inlineContext->getFullMatch() === ':(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/overview/index.html b/2.4/customization/overview/index.html new file mode 100644 index 0000000000..0f36d6e0d9 --- /dev/null +++ b/2.4/customization/overview/index.html @@ -0,0 +1,487 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders/configuration you need
  2. +
  3. Instantiate a MarkdownParser and HtmlRenderer using that Environment
  4. +
  5. Use the MarkdownParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  6. +
  7. Use the HtmlRenderer to convert the AST Document into HTML
  8. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+$environment = new Environment([
+    'html_input' => 'strip',
+]);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderDocument($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renderers convert the parsed blocks/inlines from the AST representation into HTML. When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/rendering/index.html b/2.4/customization/rendering/index.html new file mode 100644 index 0000000000..f5a728ffed --- /dev/null +++ b/2.4/customization/rendering/index.html @@ -0,0 +1,564 @@ + + + + + + + + + + + + + + + + + Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Custom Rendering

+ +

Renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement NodeRendererInterface and its render() method. Note that in v2.0, both +block renderers and inline renderers share the same interface and method:

+ +

render()

+ +
public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The HtmlRenderer will call this method during the rendering process whenever a supported element is encountered.

+ +

If your renderer can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the node and its contents, including any children. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\Util\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Renderers

+ +

When registering your renderer, you must tell the Environment which node element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// First param - the node class type that should use our renderer
+// Second param - instance of the renderer
+$environment->addRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple types:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak;
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements NodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(ThematicBreak::class, new TextDividerRenderer());
+
+ +

Note that thematic breaks should not contain children, which is why the $childRenderer is unused in this example. Otherwise we’d have to call code like this and return the result as part of the rendered HTML we’re generating here: $innerHtml = $childRenderer->renderNodes($node->children());

+ +

Tips

+ + + +

Wrapping Elements with HtmlDecorator

+ +

A utility class called HtmlDecorator is provided to make it easier to wrap the output of any renderer within an additional HTML tag with custom attributes and/or classes. To use it:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Renderer\HtmlDecorator;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\Extension\Table\TableRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(Table::class, new HtmlDecorator(new TableRenderer(), 'div', ['class' => 'table-responsive']));
+
+ +

XML Rendering

+ +

The XML renderer will automatically attempt to convert any AST nodes to XML by inspecting the name of the block/inline node and its attributes. You can instead control the XML element name and attributes by making your renderer implement XmlNodeRendererInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+
+class TextDividerRenderer implements NodeRendererInterface, XmlNodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+
+    public function getXmlTagName(Node $node): string
+    {
+        return 'text_divider';
+    }
+
+    public function getXmlAttributes(Node $node): array
+    {
+        return ['character' => '='];
+    }
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/customization/slug-normalizer/index.html b/2.4/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..3eb5d43330 --- /dev/null +++ b/2.4/customization/slug-normalizer/index.html @@ -0,0 +1,509 @@ + + + + + + + + + + + + + + + + + Slug Normalizer - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Slug Normalizer

+ +

“Slugs” are strings used within href, name, and id HTML attributes to identify particular elements within a document.

+ +

Some extensions (like the HeadingPermalinkExtension) need the ability to convert user-provided text into these URL-safe slugs while also ensuring that these are unique throughout the generated HTML. The Environment provides a pre-built normalizer you can use for this purpose.

+ +

Usage

+ +

You can obtain a reference to the built-in slug normalizer by calling $environment->getSlugNormalizer();

+ +

To use this within your extension, have your parser/renderer/whatever implement EnvironmentAwareInterface and then implement the corresponding setEnvironment method like this:

+ +

+use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Environment\EnvironmentAwareInterface;
+
+class MyCustomParserOrRenderer implements EnvironmentAwareInterface
+{
+    private $slugNormalizer;
+
+    public function setEnvironment(EnvironmentInterface $environment): void
+    {
+        $this->slugNormalizer = $environment->getSlugNormalizer();
+    }
+}
+
+ +

You can then call $this->slugNormalizer->normalize($text) as needed.

+ +

Configuration

+ +

The slug_normalizer configuration section allows you to adjust the following options:

+ +

instance

+ +

You can change the string that is used as the “slug” by setting the instance option to any class that implements TextNormalizerInterface. +We provide a simple SlugNormalizer by default, but you may want to plug in a different library or create your own normalizer instead.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

max_length

+ +

This can be configured to limit the length of that slug to prevent overly-long values. By default, that limit is 255 characters. You may set this to any positive integer, or 0 for no limit.

+ +

(Note that generated slugs might be slightly longer than this “limit” if the unique option is enabled and the slug generator detects a duplicate slug and needs to add a suffix to make it unique.)

+ +

unique

+ +

This options controls whether slugs should be unique. Possible values include:

+ + + +

You might have a use case where you’re converting several different Markdown documents on the same page and so you’d like to ensure that none of those documents use conflicting slugs. In that case, you should set the scope option to 'environment' to ensure that a single instance of a MarkdownConverter (which uses a single Environment) will never produce the same slug twice during its lifetime (which usually lasts the entire duration of a single HTTP request).

+ +

If you need complete control over how unique slugs are generated, make your 'instance' implement UniqueSlugNormalizerInterface; otherwise, we’ll simply append incremental numbers to slugs to ensure they are unique.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/attributes/index.html b/2.4/extensions/attributes/index.html new file mode 100644 index 0000000000..c85e394da4 --- /dev/null +++ b/2.4/extensions/attributes/index.html @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+ +

This results in the following output:

+ +
<blockquote title="Blockquote title">
+<p>A nice blockquote</p>
+</blockquote>
+
+ +

CSS-selector-style declarations can be used to set the id and class attributes:

+ +
{#id .class}
+## Header
+
+ +

Output:

+ +
<h2 class="class" id="id">Header</h2>
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Output:

+ +
<p>This is <em style="color: red">red</em>.</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/autolinks/index.html b/2.4/extensions/autolinks/index.html new file mode 100644 index 0000000000..48098a241c --- /dev/null +++ b/2.4/extensions/autolinks/index.html @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a Mention Parser outside of this extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/commonmark/index.html b/2.4/extensions/commonmark/index.html new file mode 100644 index 0000000000..27ee9fef97 --- /dev/null +++ b/2.4/extensions/commonmark/index.html @@ -0,0 +1,458 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically installed for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new Environment with the core extension
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/default-attributes/index.html b/2.4/extensions/default-attributes/index.html new file mode 100644 index 0000000000..597790430f --- /dev/null +++ b/2.4/extensions/default-attributes/index.html @@ -0,0 +1,527 @@ + + + + + + + + + + + + + + + + + Default Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Default Attributes

+ +

The DefaultAttributesExtension allows you to apply default HTML classes and other attributes using configuration options.

+ +

It works by applying the attributes to the nodes during the DocumentParsedEvent event - right after the nodes are parsed but before they are rendered. +(As a result, it’s possible that renderers may add other attributes - the goal of this extension is only to provide custom defaults.)

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DefaultAttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Node\Block\Paragraph;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'default_attributes' => [
+        Heading::class => [
+            'class' => static function (Heading $node) {
+                if ($node->getLevel() === 1) {
+                    return 'title-main';
+                } else {
+                    return null;
+                }
+            },
+        ],
+        Table::class => [
+            'class' => 'table',
+        ],
+        Paragraph::class => [
+            'class' => ['text-center', 'font-comic-sans'],
+        ],
+        Link::class => [
+            'class' => 'btn btn-link',
+            'target' => '_blank',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new DefaultAttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a default_attributes array. Each key in the array should be a FQCN for the node class you wish to apply the default attribute to, and the values should be a map of attribute names to attribute values.

+ +

Attribute values may be any of the following types:

+ + + +

Examples

+ +

Here’s an example that will apply Bootstrap 4 classes and attributes:

+ +
$config = [
+    'default_attributes' => [
+        Table::class => [
+            'class' => ['table', 'table-responsive'],
+        ],
+        BlockQuote::class => [
+            'class' => 'blockquote',
+        ],
+    ],
+];
+
+ +

Here’s a more complex example that uses a callable to add a class only if the paragraph immediately follows an <h1> heading:

+ +
$config = [
+    'default_attributes' => [
+        Paragraph::class => [
+            'class' => static function (Paragraph $paragraph) {
+                if ($paragraph->previous() instanceof Heading && $paragraph->previous()->getLevel() === 1) {
+                    return 'lead';
+                }
+
+                return null;
+            },
+        ],
+    ],
+];
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/description-lists/index.html b/2.4/extensions/description-lists/index.html new file mode 100644 index 0000000000..b118bd451f --- /dev/null +++ b/2.4/extensions/description-lists/index.html @@ -0,0 +1,477 @@ + + + + + + + + + + + + + + + + + Description List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Description List Extension

+ +

The DescriptionListExtension adds Markdown Extra-style description lists to facilitate the creation of <dl>, <dt>, and <dd> HTML using Markdown.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DescriptionListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\DescriptionList\DescriptionListExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DescriptionListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some markdown goes here');
+
+ +

Syntax

+ +

The syntax is based directly on the rules and logic implemented by the Markdown Extra library. Here are some examples of sample Markdown input and HTML output demonstrating the syntax:

+ +
Apple
+:   Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.
+:   An American computer company.
+
+Orange
+:   The fruit of an evergreen tree of the genus Citrus.
+
+ +
<dl>
+    <dt>Apple</dt>
+    <dd>Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.</dd>
+    <dd>An American computer company.</dd>
+
+    <dt>Orange</dt>
+    <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+
+ +

See the Markdown Extra documentation or our own spec for additional examples.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/disallowed-raw-html/index.html b/2.4/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..7b20b99dd7 --- /dev/null +++ b/2.4/extensions/disallowed-raw-html/index.html @@ -0,0 +1,484 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically escapes certain HTML tags when rendering raw HTML, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Customize the extension's configuration if needed
+// Default values are shown below - you can omit this configuration if you're happy with those defaults
+// and don't want to customize them
+$config = [
+    'disallowed_raw_html' => [
+        'disallowed_tags' => ['title', 'textarea', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'script', 'plaintext'],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I cannot change the page <title>anymore</title>');
+
+ +

Configuration

+ +

This extension can be configured by providing a disallowed_raw_html array with the following nested configuration options. The defaults are shown in the code example above.

+ +

disallowed_tags

+ +

An array containing a list of tags that should be escaped.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/embed/index.html b/2.4/extensions/embed/index.html new file mode 100644 index 0000000000..e9ee50d60c --- /dev/null +++ b/2.4/extensions/embed/index.html @@ -0,0 +1,556 @@ + + + + + + + + + + + + + + + + + Embed Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Embed Extension

+ +

This extension can embed rich content (like videos, tweets, etc.) from other websites.

+ +

The syntax is very simple - simply place any https:// URL on its own line like this:

+ +
Check out this video!
+
+https://www.youtube.com/watch?v=dQw4w9WgXcQ
+
+ +

If the link points to embeddable content, it will be replaced with the rich HTML needed to embed it:

+ +
<p>Check out this video:</p>
+<iframe width="200" height="113" src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

You’ll also need to install a third-party OEmbed library - see the Adapter section below.

+ +

Usage

+ +

Configure your Environment as usual and add the EmbedExtension provided by this package:

+ +
use Embed\Embed;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Embed\EmbedExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'embed' => [
+        'adapter' => new OscaroteroEmbedAdapter(), // See the "Adapter" documentation below
+        'allowed_domains' => ['youtube.com', 'twitter.com', 'github.com'],
+        'fallback' => 'link',
+    ],
+];
+
+// Configure the Environment with all whatever other extensions you want
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new EmbedExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
+
+ +

Configuration

+ +

This extension supports the following configuration options under the embed configuration:

+ +

adapter option

+ +

Any instance of EmbedAdapterInterface - see the “Adapter” section below.

+ +

allowed_domains option

+ +

This option defines a list of hosts that you wish to allow embedding content from. For example, setting this to +['youtube.com'] would only allow videos from YouTube to be embedded. +It’s extremely important that you only include websites you trust since they’ll be providing HTML that is directly embedded in your website.

+ +

Any subdomains of these domains will also be allowed. For example, ['youtube.com'] would allow embedding from youtube.com or www.youtube.com.

+ +

As an additional safety measure, we recommend that you also use a Content Security Policy (CSP) +to prevent unexpected content from being embedded.

+ +

By default, this option is an empty array ([]), which means that all domains are allowed.

+ +

fallback option

+ +

This options defines the behavior when a URL cannot be embedded, either because it’s not in the list of allowed_domains, +or because the adapter could not find embeddable content for that URL.

+ +

There are two possible values for this option:

+ + + +

Adapter

+ +

league/commonmark doesn’t know how to obtain the embeddable HTML for a given URL - this must be done by an external library.

+ +

embed/embed Adapter

+ +

We do provide an adapter for the popular embed/embed library. if you’d like to use that. We like this library +because it supports fetching multiple URLs in parallel, which is ideal for performance, and it supports a wide range +of embeddable content.

+ +

To use that library, you’ll need to composer require embed/embed and then pass new OscaroteroEmbedAdapter() as the adapter +configuration option, as shown in the Usage section above.

+ +

Need to customize the maximum width/height of the embedded content? You can do that by instantiating the service provided by +embed/embed, configuring it as needed, and passing that customized instance into the adapter:

+ +
use Embed\Embed;
+use League\CommonMark\Extension\Embed\Bridge\OscaroteroEmbedAdapter;
+
+// Configure the Embed library itself
+$embedLibrary = new Embed();
+$embedLibrary->setSettings([
+    'oembed:query_parameters' => [
+        'maxwidth' => 800,
+        'maxheight' => 600,
+    ],
+    'twitch:parent' => 'example.com',
+    'facebook:token' => '1234|5678',
+    'instagram:token' => '1234|5678',
+    'twitter:token' => 'asdf',
+]);
+
+// Inject it into our adapter
+$config = [
+    'adapter' => new OscaroteroEmbedAdapter($embedLibrary),
+];
+
+// Instantiate your CommonMark environment and converter like usual
+// ...
+
+ +

Custom Adapter

+ +

If you prefer to use a different library, you’ll need to implement our EmbedAdapterInterface yourself with +whatever OEmbed library you choose.

+ +

Tips

+ +

If you need to wrap the HTML in a container tag, consider using the HtmlDecorator renderer:

+ +
$environment->addRenderer(Embed::class, new HtmlDecorator(new EmbedRenderer(), 'div', ['class' => 'embeded-content']));
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/external-links/index.html b/2.4/extensions/external-links/index.html new file mode 100644 index 0000000000..a81d062f97 --- /dev/null +++ b/2.4/extensions/external-links/index.html @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class MyCustomLinkRenderer implements NodeRendererInterface
+{
+    /**
+     * @param Node                       $node
+     * @param ChildNodeRendererInterface $childRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        Link::assertInstanceOf($node);
+
+        if ($node->data->get('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/footnotes/index.html b/2.4/extensions/footnotes/index.html new file mode 100644 index 0000000000..d36533977a --- /dev/null +++ b/2.4/extensions/footnotes/index.html @@ -0,0 +1,564 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1"></a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'backref_symbol'     => '↩',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

backref_symbol

+ +

This string option sets the symbol used as the contents of the footnote backreference link. It defaults to \League\CommonMark\Extension\Footnote\Renderer\FootnoteBackrefRenderer::DEFAULT_SYMBOL = '↩'.

+ +

If you want to use a custom icon, set this to an empty string '' and take a look at the Adding Icons section below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ +

Adding Icons

+ +

You can use CSS to add a custom icon instead of providing a backref_symbol:

+ +
$config = [
+    'footnote' => [
+        'backref_class' => 'footnote-backref',
+        'backref_symbol' => '',
+    ],
+];
+
+ +

Then target the backref_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.footnote-backref::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/front-matter/index.html b/2.4/extensions/front-matter/index.html new file mode 100644 index 0000000000..96b26eca10 --- /dev/null +++ b/2.4/extensions/front-matter/index.html @@ -0,0 +1,550 @@ + + + + + + + + + + + + + + + + + Front Matter Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Front Matter Extension

+ +

The FrontMatterExtension adds the ability to parse YAML front matter from the Markdown document and include that in the return result.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

You will also need to install symfony/yaml or the YAML extension for PHP to use this extension. For symfony/yaml:

+ +
composer require symfony/yaml
+
+ +

(You can use any version of symfony/yaml 2.4 or higher, though we recommend using 4.0 or higher.)

+ +

Front Matter Syntax

+ +

This extension follows the Jekyll Front Matter syntax. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:

+ +
---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+
+ +

This will produce a front matter array similar to this:

+ +
$parsedFrontMatter = [
+    'layout' => 'post',
+    'title' => 'I Love Markdown',
+    'tags' => [
+        'test',
+        'example',
+    ],
+];
+
+ +

And the HTML output will only contain the one heading:

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

Usage

+ +

Configure your Environment as usual and add the FrontMatterExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FrontMatterExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+// A sample Markdown file with some front matter:
+$markdown = <<<MD
+---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+MD;
+
+$result = $converter->convert($markdown);
+
+// Grab the front matter:
+if ($result instanceof RenderedContentWithFrontMatter) {
+    $frontMatter = $result->getFrontMatter();
+}
+
+// Output the HTML using any of these:
+echo $result;               // implicit string cast
+// or:
+echo (string) $result;      // explicit string cast
+// or:
+echo $result->getContent();
+
+ +

Parsing Front Matter Only

+ +

You don’t have to parse the entire file (including all the Markdown) if you only want the front matter. You can either instantiate the front matter parser yourself and call it directly, like this:

+ +
use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+// For `symfony/yaml`
+$frontMatterParser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
+// For YAML extension
+$frontMatterParser = new FrontMatterParser(new LibYamlFrontMatterParser());
+$result = $frontMatterParser->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

Or you can use the getFrontMatterParser() method from the extension:

+ +
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+$frontMatterExtension = new FrontMatterExtension();
+$result = $frontMatterExtension->getFrontMatterParser()->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

This latter approach may be more convenient if you have already instantiated a FrontMatterExtension object you’re adding to the Environment somewhere and just want to call that.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/github-flavored-markdown/index.html b/2.4/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..ee8df59b11 --- /dev/null +++ b/2.4/extensions/github-flavored-markdown/index.html @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark and GFM parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/heading-permalinks/index.html b/2.4/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..3dc74fd7e3 --- /dev/null +++ b/2.4/extensions/heading-permalinks/index.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'content',
+        'apply_id_to_heading' => false,
+        'heading_class' => '',
+        'fragment_prefix' => 'content',
+        'insert' => 'before',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'aria_hidden' => true,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

apply_id_to_heading

+ +

If this value is true, the id attributes will be written to the <h> tag instead of the <a>.

+ +

heading_class

+ +

The class will be added to the <h> tag (no matter if apply_id_to_heading is set true or false)

+ +

fragment_prefix

+ +

This should be a string you want prepended to the URL fragment in the link’s href attribute. This should typically be set to the same value as id_prefix for links to work properly. However, you may not want to expose that same prefix in your URLs - in that case, you can set this to something different (even an empty string) and use JavaScript to “rewrite” them.

+ +

For example, to emulate how GitHub heading permalinks work, set id_prefix to 'user-content', set fragment_prefix to '', and insert some JavaScript into the page like this:

+ +
var scrollToPermalink = function() {
+    var link = document.getElementById('user-content-' + window.location.hash);
+    if (link) {
+        link.scrollIntoView({behavior: 'smooth'});
+    }
+};
+
+window.addEventListener('hashchange', scrollToPermalink);
+if (window.location.hash) {
+    scrollToPermalink();
+}
+
+ +

insert

+ +

This controls whether the anchor is added to the beginning of the heading tag (before), the end of the tag (after), or not added at all (none).

+ +

min_heading_level and max_heading_level

+ +

These two settings control which headings should have permalinks added. By default, all 6 levels (1, 2, 3, 4, 5, and 6) will have them. You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

aria_hidden

+ +

This option sets the aria-hidden attribute on the <a> tag. This defaults to aria-hidden="true".

+ +

Setting this option to false would render the <a> tag excluding the aria-hidden entirely.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/inlines-only/index.html b/2.4/extensions/inlines-only/index.html new file mode 100644 index 0000000000..ad461d12a5 --- /dev/null +++ b/2.4/extensions/inlines-only/index.html @@ -0,0 +1,448 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new, empty environment
+$environment = new Environment($config);
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/mentions/index.html b/2.4/extensions/mentions/index.html new file mode 100644 index 0000000000..0a807877ad --- /dev/null +++ b/2.4/extensions/mentions/index.html @@ -0,0 +1,674 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting prefix, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the first mention parser to
+        // successfully match and return a properly constructed Mention object (where the URL has been set) will be the
+        // the mention parser that is used. In this example, the GitHub handle would actually match first because
+        // there isn't any real validation to check whether https://www.github.com/colinodell exists. However, in
+        // CMS applications, you could check whether its a local user first, then check Twitter and then GitHub, etc.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on GitHub: @colinodell');
+// Output:
+// <p>Follow me on GitHub: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regular expression pattern (without opening/closing delimiter or modifiers), or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Inline\Element\AbstractInline;
+
+class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/overview/index.html b/2.4/extensions/overview/index.html new file mode 100644 index 0000000000..5e6026f570 --- /dev/null +++ b/2.4/extensions/overview/index.html @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Default AttributesEasily apply default HTML classes using configuration options to match your site’s styles2.0.0 
Description ListsCreate <dl> description lists using Markdown Extra’s syntax2.0.0 
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
EmbedEmbed rich content (like videos, tweets, and more) from other websites2.3.0 
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
Front MatterParses YAML front matter from your Markdown input2.0.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the extensions you need
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the other extensions you need
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/smart-punctuation/index.html b/2.4/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..5f9f6495c6 --- /dev/null +++ b/2.4/extensions/smart-punctuation/index.html @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/strikethrough/index.html b/2.4/extensions/strikethrough/index.html new file mode 100644 index 0000000000..5e9c55e485 --- /dev/null +++ b/2.4/extensions/strikethrough/index.html @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/table-of-contents/index.html b/2.4/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..3cdf3aba3c --- /dev/null +++ b/2.4/extensions/table-of-contents/index.html @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
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;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/tables/index.html b/2.4/extensions/tables/index.html new file mode 100644 index 0000000000..f49c6280ac --- /dev/null +++ b/2.4/extensions/tables/index.html @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => false,
+            'tag' => 'div',
+            'attributes' => [],
+        ],
+        'alignment_attributes' => [
+            'left'   => ['align' => 'left'],
+            'center' => ['align' => 'center'],
+            'right'  => ['align' => 'right'],
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Configuration

+ +

Wrapping Container

+ +

You can “wrap” the table with a container element by configuring the following options:

+ + + +

For example, to wrap all tables within a <div class="table-responsive"> container element:

+ +
$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => true,
+            'tag' => 'div',
+            'attributes' => ['class' => 'table-responsive'],
+        ],
+    ],
+];
+
+ +

Alignment

+ +

You can configure the HTML attributes used for alignment via the alignment_attributes option. For example, if you wanted Bootstrap classes to be applied, you could do so like this:

+ +
$config = [
+    'table' => [
+        'alignment_attributes' => [
+            'left' => ['class' => 'text-start'],
+            'center' => ['class' => 'text-center'],
+            'right' => ['class' => 'text-end'],
+        ],
+    ],
+];
+
+ +

Or you could use inline styles:

+ +
$config = [
+    'table' => [
+        'alignment_attributes' => [
+            'left' => ['style' => 'text-align:left'],
+            'center' => ['style' => 'text-align:center'],
+            'right' => ['style' => 'text-align:right'],
+        ],
+    ],
+];
+
+ +

Or any other HTML attributes you’d like!

+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/extensions/task-lists/index.html b/2.4/extensions/task-lists/index.html new file mode 100644 index 0000000000..891478b616 --- /dev/null +++ b/2.4/extensions/task-lists/index.html @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convert($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/index.html b/2.4/index.html new file mode 100644 index 0000000000..1841692b31 --- /dev/null +++ b/2.4/index.html @@ -0,0 +1,451 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello, World!')->getContent();
+
+// <h1>Hello, World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/installation/index.html b/2.4/installation/index.html new file mode 100644 index 0000000000..a2451e227b --- /dev/null +++ b/2.4/installation/index.html @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Installation

+ +

The recommended installation method is via Composer.

+ +
composer require "league/commonmark:^2.4"
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^2.4. This is equivalent to >=2.4 <3.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/security/index.html b/2.4/security/index.html new file mode 100644 index 0000000000..6b209a4efd --- /dev/null +++ b/2.4/security/index.html @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convert($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/support/index.html b/2.4/support/index.html new file mode 100644 index 0000000000..f6efa4fdc1 --- /dev/null +++ b/2.4/support/index.html @@ -0,0 +1,433 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/upgrading/index.html b/2.4/upgrading/index.html new file mode 100644 index 0000000000..f92f207ce5 --- /dev/null +++ b/2.4/upgrading/index.html @@ -0,0 +1,434 @@ + + + + + + + + + + + + + + + + + Upgrading from 2.3 to 2.4 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

Upgrading from 2.3 to 2.4

+ +

Exception Changes

+ +

Prior to 2.4.0, this library did a poor job of using appropriate exception types and documenting which exceptions could +be thrown. For example, all of the main interfaces said that only RuntimeException could be thrown, but in reality +other exceptions like LogicException or InvalidArgumentException could be thrown in some cases!

+ +

This inconsistent behavior and inaccurate documentation has been fixed in 2.4.0 by:

+ + + +

If you were previously catching exceptions thrown by this library in your code, you should consider changing your +catch blocks to either catch CommonMarkException (for all exceptions) or one of the exception types under the +League\CommonMark\Exception namespace.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.4/xml/index.html b/2.4/xml/index.html new file mode 100644 index 0000000000..f6601302e7 --- /dev/null +++ b/2.4/xml/index.html @@ -0,0 +1,454 @@ + + + + + + + + + + + + + + + + + XML Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + +

This is the documentation for version 2.4. Please consider upgrading your code to the latest stable version

+ + + + +

XML Rendering

+ +

Version 2.0 introduced the ability to render Markdown Document objects in XML. This is particularly useful for debugging custom extensions as you can see the XML representation of the Abstract Syntax Tree.

+ +

To convert Markdown to XML, you would instantiate a MarkdownToXmlConverter with an Environment and then call convert() on any Markdown.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Xml\MarkdownToXmlConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$converter = new MarkdownToXmlConverter($environment);
+
+echo $converter->convert('# **Hello** World!');
+
+ +

This will display XML output like this:

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<document xmlns="http://commonmark.org/xml/1.0">
+    <heading level="1">
+        <strong>
+            <text>Hello</text>
+        </strong>
+        <text> World!</text>
+    </heading>
+</document>
+
+ +

Alternatively, if you already have a Document object you want to visualize in XML, you can use theXmlRenderer class to convert it to XML.

+ +

Return Value

+ +

Like with CommonMarkConverter::convert(), the renderDocument() actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final XML output.

+ +

Customizing the XML Output

+ +

See the rendering documentation for information on customizing the XML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/basic-usage/index.html b/2.5/basic-usage/index.html new file mode 100644 index 0000000000..a26e7226a7 --- /dev/null +++ b/2.5/basic-usage/index.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + Basic Usage - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Basic Usage

+ +

+Important: See the security section for important details on avoiding security misconfigurations.

+ +

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

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Or if you want GitHub-Flavored Markdown:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new GithubFlavoredMarkdownConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Using Extensions

+ +

The CommonMarkConverter and GithubFlavoredMarkdownConverter shown above automatically configure the environment for you, but if you want to use additional extensions you’ll need to avoid those classes and use the generic MarkdownConverter class instead to customize the environment with whatever extensions you wish to use:

+ +
require __DIR__ . '/vendor/autoload.php';
+
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+
+$environment->addExtension(new InlinesOnlyExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+// <p><strong>Hello World!</strong></p>
+
+ +

Configuration

+ +

If you’re using the CommonMarkConverter or GithubFlavoredMarkdownConverter class you can pass configuration options directly into their constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

See the configuration section for more information on the available configuration options.

+ +

Supported Character Encodings

+ +

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.

+ +

Return Value

+ +

The convert() method actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final HTML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/changelog/index.html b/2.5/changelog/index.html new file mode 100644 index 0000000000..040c08c262 --- /dev/null +++ b/2.5/changelog/index.html @@ -0,0 +1,515 @@ + + + + + + + + + + + + + + + + + Changelog - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Changelog

+ +

All notable changes made in 2.x releases are shown below. See the full list of releases for the complete changelog.

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

Older Versions

+ +

Please see the full list of releases for the complete changelog.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/configuration/index.html b/2.5/configuration/index.html new file mode 100644 index 0000000000..08d6d20c63 --- /dev/null +++ b/2.5/configuration/index.html @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Configuration

+ +

Many aspects of this library’s behavior can be tweaked using configuration options.

+ +

You can provide an array of configuration options to the Environment or converter classes when creating them:

+ +
$config = [
+    'renderer' => [
+        'block_separator' => "\n",
+        'inner_separator' => "\n",
+        'soft_break'      => "\n",
+    ],
+    'commonmark' => [
+        'enable_em' => true,
+        'enable_strong' => true,
+        'use_asterisk' => true,
+        'use_underscore' => true,
+        'unordered_list_markers' => ['-', '*', '+'],
+    ],
+    'html_input' => 'escape',
+    'allow_unsafe_links' => false,
+    'max_nesting_level' => PHP_INT_MAX,
+    'slug_normalizer' => [
+        'max_length' => 255,
+    ],
+];
+
+ +

If you’re using the basic CommonMarkConverter or GithubFlavoredMarkdown classes, simply pass the configuration array into the constructor:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\GithubFlavoredMarkdownConverter;
+
+$converter = new CommonMarkConverter($config);
+// or
+$converter = new GithubFlavoredMarkdownConverter($config);
+
+ +

Otherwise, if you’re using MarkdownConverter to customize the extensions in your parser, pass the configuration into the Environment’s constructor instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Here's where we set the configuration array:
+$environment = new Environment($config);
+
+// TODO: Add any/all the extensions you wish; for example:
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Go forth and convert you some Markdown!
+$converter = new MarkdownConverter($environment);
+
+ +

Here’s a list of the core configuration options available:

+ + + +

Additional configuration options are available for most of the available extensions - refer to their individual documentation for more details. For example, the CommonMark core extension offers these additional options:

+ + + +

Environment

+ +

The configuration is ultimately passed to (and managed via) the Environment. If you’re creating your own Environment, simply pass your config array into its constructor instead.

+ +

Learn more about customizing the Environment

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/abstract-syntax-tree/index.html b/2.5/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..e0e0549441 --- /dev/null +++ b/2.5/customization/abstract-syntax-tree/index.html @@ -0,0 +1,708 @@ + + + + + + + + + + + + + + + + + Abstract Syntax Tree - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Abstract Syntax Tree

+ +

This library uses a doubly-linked list Abstract Syntax Tree (AST) to represent the parsed block and inline elements. All such elements extend from the Node class.

+ +

Document

+ +

The root node of the AST will always be a Document object. You can obtain this node a few different ways:

+ + + +

Visualization

+ +

Even with an interactive debugger it can be tricky to view an entire tree at once. Consider using the XmlRenderer to provide a simple text-based representation of the AST for debugging purposes.

+ +

Node Traversal

+ +

There are four different ways to traverse/iterate the Nodes within the AST:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodProsCons
Manual TraversalBest way to access/check direct relatives of nodesNot useful for iteration
Iterating the TreeFast and efficientPossible unexpected behavior when adding/removing sibling nodes while iterating
Walking the TreeFull control over iterationUp to twice as slow as iteration; adding/removing nodes while iterating can lead to weird behaviors
Querying NodesEasier to write and understand; no weird behaviorsNot memory efficient
+ +

Each is described in more detail below

+ +

Manual Traversal

+ +

The following methods can be used to manually traverse from one Node to any of its direct relatives:

+ + + +

This is best suited for situations when you need to know information about those relatives.

+ +

Iterating the Tree

+ +

If you’d like to iterate through all the nodes, use the iterator() method to obtain an iterator that will loop through each node in the tree (using pre-order traversal):

+ +
foreach ($document->iterator() as $node) {
+    echo 'Current node: ' . get_class($node) . "\n";
+}
+
+ +

Given an AST like this (XML representation):

+ +
<document>
+  <heading level="1">
+    <text>Hello World!</text>
+  </heading>
+  <paragraph>
+    <text>This is an example of </text>
+    <strong>
+      <text>CommonMark</text>
+    </strong>
+    <text>.</text>
+  </paragraph>
+</document>
+
+ +

The code above will output:

+ +
Current node: League\CommonMark\Node\Block\Document
+Current node: League\CommonMark\Extension\CommonMark\Node\Block\Heading
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Block\Paragraph
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Extension\CommonMark\Node\Inline\Strong
+Current node: League\CommonMark\Node\Inline\Text
+Current node: League\CommonMark\Node\Inline\Text
+
+ +

This iterator doesn’t use recursion, so you won’t blow the stack when working with deeply-nested nodes. It’s also very CPU and memory-efficient.

+ +

Be careful when modifying nodes while iterating the tree as some of those changes may affect the current iteration process, especially for sibling nodes that come after the current one. For example, if you remove the current node’s next() sibling, the next loop of that iteration will still include the removed sibling even though it was successfully removed from the AST. Similarly, any new siblings that are added won’t be visited on the next loop.

+ +

Walking the Tree

+ +

If you’d like to walk through all the nodes, visiting each one as you enter and leave it, use the walker() method to obtain an instance of NodeWalker. This also uses pre-order traversal but emitting NodeWalkerEvents along the way:

+ +
use League\CommonMark\Node\NodeWalker;
+
+/** @var NodeWalker $walker */
+$walker = $document->walker();
+while ($event = $walker->next()) {
+    echo 'Now ' . ($event->isEntering() ? 'entering' : 'leaving') . ' a ' . get_class($event->getNode()) . ' node' . "\n";
+}
+
+ +

Using the same example AST in the previous section, this code will output:

+ +
Now entering a League\CommonMark\Node\Block\Document node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Block\Heading node
+Now entering a League\CommonMark\Node\Block\Paragraph node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now entering a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Extension\CommonMark\Node\Inline\Strong node
+Now entering a League\CommonMark\Node\Inline\Text node
+Now leaving a League\CommonMark\Node\Block\Paragraph node
+Now leaving a League\CommonMark\Node\Block\Document node
+
+ +

This approach offers many of the same benefits as the simple iteration shown in the previous section such as memory efficiency and no recursion. The key differences come from how you enter and leave nodes:

+ +
    +
  1. Iteration can potentially take twice as long - not ideal for performance
  2. +
  3. Provides you with more control over exactly when an action is taken on a node which is sometimes needed for certain AST manipulations
  4. +
  5. Also provides a resumeAt() method to override where it should iterate next
  6. +
+ +

But like with the iterator, be careful when adding/removing nodes while walking the tree, as there are even more subtle cases where the walker could even lose track of where it was, which may result in some nodes being visited multiple times or not at all.

+ +

Querying Nodes

+ +

If you’re trying to locate certain nodes to perform actions on them, querying the nodes from the AST might be easier to implement. This can be done with the Query class:

+ +
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Node\Block\Paragraph;
+use League\CommonMark\Node\Query;
+
+// Find all paragraphs and blockquotes that contain links
+$matchingNodes = (new Query())
+    ->where(Query::type(Paragraph::class))
+    ->orWhere(Query::type(BlockQuote::class))
+    ->andWhere(Query::hasChild(Query::type(Link::class)))
+    ->findAll($document);
+
+foreach ($matchingNodes as $node) {
+    // TODO: Do something with them
+}
+
+ +

Each condition passed into where(), orWhere(), or andWhere() must be a callable “filter” that accepts a Node and returns true or false. We provide several methods that can help create these filters for you:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodDescription
Query::type(string $class)Creates a filter that matches nodes with the given class name
Query::hasChild()Creates a filter that matches nodes which contain at least one child
Query::hasChild(callable $condition)Creates a filter that matches nodes which contain at least one child that matches the inner $condition
Query::hasParent()Creates a filter that matches nodes which have a parent
Query::hasParent(callable $condition)Creates a filter that matches nodes which have a parent that matches the inner $condition
+ +

You can of course create your own custom filters/conditions using an anonymous function or by implementing ExpressionInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Node\Query;
+use League\CommonMark\Node\Query\ExpressionInterface;
+
+class ChildCountGreaterThan implements ExpressionInterface
+{
+    private $count;
+
+    public function __construct(int $count)
+    {
+        $this->count = $count;
+    }
+
+    public function __invoke(Node $node) : bool{
+        return count($node->children()) > $this->count;
+    }
+}
+
+$query = (new Query())
+    ->where(function (Node $node): bool { return $node->data->has('attributes/class'); })
+    ->andWhere(new ChildCountGreaterThan(3));
+
+ +

Modification

+ +

The following methods can be used to modify the AST:

+ + + +

DocumentParsedEvent

+ +

The best way to access and manipulate the AST is by adding an event listener for the DocumentParsedEvent.

+ +

Data Storage

+ +

Each Node has a property called data which is a Data (array-like) object. This can be used to store any arbitrary data you’d like on the node:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text1 = new Text('Hello, world!');
+$text1->data->set('language', 'English');
+$text1->data->set('is_good_translation', true);
+
+$text2 = new Text('Bonjour monde!');
+$text2->data->set('language', 'French');
+$text2->data->set('is_good_translation', false);
+
+foreach ([$text1, $text2] as $text) {
+    if ($text->data->get('is_good_translation')) {
+        sprintf('In %s we would say: "%s"', $text->data->get('language'), $text->getLiteral());
+    } else {
+        sprintf('I think they would say "%s" in %s, but I\'m not sure.', $text->getLiteral(), $text->data->get('language'));
+    }
+}
+
+ +

You can also access deeply-nested paths using / or . as delimiters:

+ +
use League\CommonMark\Node\Inline\Text;
+
+$text = new Text('Hello, world!');
+$text->data->set('info', ['language' => 'English', 'is_good_translation' => true]);
+
+var_dump($text->data->get('info/language'));
+var_dump($text->data->get('info.is_good_translation'));
+
+$text->data->set('info/is_example', true);
+
+ +

HTML Attributes

+ +

The data property comes pre-instantiated with a single data element called attributes which is used to store any HTML attributes that need to be rendered. For example:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+$link = new Link('https://twitter.com/colinodell', '@colinodell');
+$link->data->append('attributes/class', 'social-link');
+$link->data->append('attributes/class', 'twitter');
+$link->data->set('attributes/target', '_blank');
+$link->data->set('attributes/rel', 'noopener');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/block-parsing/index.html b/2.5/customization/block-parsing/index.html new file mode 100644 index 0000000000..ae95edab82 --- /dev/null +++ b/2.5/customization/block-parsing/index.html @@ -0,0 +1,552 @@ + + + + + + + + + + + + + + + + + Block Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Block Parsing

+ +

At a high level, block parsing is a two-step process:

+ +
    +
  1. Using a BlockStartParserInterface to identify if/where a block start exists on the given line
  2. +
  3. Using a BlockContinueParserInterface to perform additional processing of the identified block
  4. +
+ +

So to implement a custom block parser you will actually need to implement both of these classes.

+ +

BlockStartParserInterface

+ +

Instances of this interface have a single tryStart() method:

+ +
/**
+ * Check whether we should handle the block at the current position
+ *
+ * @param Cursor                       $cursor
+ * @param MarkdownParserStateInterface $parserState
+ *
+ * @return BlockStart|null
+ */
+public function tryStart(Cursor $cursor, MarkdownParserStateInterface $parserState): ?BlockStart;
+
+ +

Given a Cursor at the current position, plus some extra information about the state of the parser, this method is responsible for determining whether a particular type of block seems to exist at the given position. You don’t actually parse the block here - that’s the job of a BlockContinueParserInterface. Your only job here is to return whether or not a particular type of block does exist here, and if so which block parser should parse it.

+ +

If you find that you cannot parse the given block, you should return BlockStart::none(); from this function.

+ +

However, if the Markdown at the current position does indeed seem to be the type of block you’re looking for, you should return a BlockStart instance using the following static constructor pattern:

+ +
use League\CommonMark\Parser\Block\BlockStart;
+
+return BlockStart::of(new MyCustomParser())->at($cursor);
+
+ +

Unlike in 1.x, the Cursor state is no longer shared between parsers. You must therefore explicitly provide the BlockStart object with a copy of your cursor at the correct, post-parsing position.

+ +

NOTE: If your custom block starts with a letter character you’ll need to add your parser to the environment with a priority of 250 or higher. This is due to a performance optimization where such lines are usually skipped.

+ +

BlockContinueParserInterface

+ +

The previous interface only helps the engine identify where a block starts. Additional information about the block, as well as the ability to parse additional lines of input, is all handled by the BlockContinueParserInterface.

+ +

This interface has several methods, so it’s usually easier to extend from AbstractBlockContinueParser instead, which sets most of the methods to use typical defaults you can override as needed.

+ +

getBlock()

+ +
public function getBlock(): AbstractBlock;
+
+ +

Each instance of a BlockContinueParserInterface is associated with a new block that is being parsed. This method here returns that block.

+ +

isContainer()

+ +
public function isContainer(): bool;
+
+ +

This method returns whether or not the block is a “container” capable of containing other blocks as children.

+ +

canContain()

+ +
public function canContain(AbstractBlock $childBlock): bool;
+
+ +

This method returns whether the current block being parsed can contain the given child block.

+ +

canHaveLazyContinuationLines()

+ +
public function canHaveLazyContinuationLines(): bool;
+
+ +

This method returns whether or not this parser should also receive subsequent lines of Markdown input. This is primarily used when a block can span multiple lines, like code blocks do.

+ +

addLine()

+ +
public function addLine(string $line): void;
+
+ +

If canHaveLazyContinuationLines() returned true, this method will be called with the additional lines of content.

+ +

tryContinue()

+ +
public function tryContinue(Cursor $cursor, BlockContinueParserInterface $activeBlockParser): ?BlockContinue;
+
+ +

This method allows you to try and parse an additional line of Markdown.

+ +

closeBlock()

+ +
public function closeBlock(): void;
+
+ +

This method is called when the block is done being parsed. Any final adjustments to the block should be made at this time.

+ +

parseInlines()

+ +
public function parseInlines(InlineParserEngineInterface $inlineParser): void;
+
+ +

This method is called when the engine is ready to parse any inline child elements.

+ +

Note: For performance reasons, this method is not part of BlockContinueParserInterface. If your block may contain inlines, you should make sure that your “continue parser” also implements BlockContinueParserWithInlinesInterface.

+ +

Tips

+ +

Here are some additional tips to consider when writing your own custom parsers:

+ +

Combining both into one file

+ +

Although parsing requires two classes, you can use the anonymous class feature of PHP to combine both into a single file! Here’s an example:

+ +
use League\CommonMark\Parser\Block\AbstractBlockContinueParser;
+use League\CommonMark\Parser\Block\BlockStartParserInterface;
+
+final class MyCustomBlockParser extends AbstractBlockContinueParser
+{
+    // TODO: implement your continuation parsing methods here
+
+    public static function createBlockStartParser(): BlockStartParserInterface
+    {
+        return new class implements BlockStartParserInterface
+        {
+            // TODO: implement the tryStart() method here
+        };
+    }
+}
+
+
+ +

Performance

+ +

The BlockStartParserInterface::tryStart() and BlockContinueParserInterface::tryContinue() methods may be called hundreds or thousands of times during execution. For best performance, have your methods return as early as possible, and make sure your code is highly optimized.

+ +

Block Elements

+ +

In addition to creating a block parser, you may also want to have it return a custom “block element” - this is a class that extends from AbstractBlock and represents that particular block within the AST.

+ +

If your block contains literal strings/text within the block (and not as part of a child block), you should have your custom block type also implement StringContainerInterface.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/configuration/index.html b/2.5/customization/configuration/index.html new file mode 100644 index 0000000000..0b51b2703f --- /dev/null +++ b/2.5/customization/configuration/index.html @@ -0,0 +1,508 @@ + + + + + + + + + + + + + + + + + Configuration - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Configuration Schemas and Values

+ +

Version 2.0 introduced a new robust system for defining configuration schemas and accessing them within custom extensions.

+ +

Configuration Schemas

+ +

Unlike in 1.x, all configuration options must have a defined schema. This defines which options are available, what types of values they accept, whether any are required, and any default values you wish to define if the user doesn’t provide any.

+ +

These custom options can be defined from within your custom extension by implementing the ConfigurableExtensionInterface:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+use Nette\Schema\Expect;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        $builder->addSchema('my_extension', Expect::structure([
+            'enable_some_feature' => Expect::bool()->default(true),
+            'html_class' => Expect::string()->default('my-custom-extension'),
+            'align' => Expect::anyOf('left', 'center', 'right')->default('left'),
+            'favorite_number' => Expect::int()->min(1)->max(100)->default(42),
+        ]));
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        // TODO: Implement register() method
+    }
+}
+
+ +

See the league/config documentation for more examples of how to define custom configuration schemas.

+ +

Note that you only need to implement ConfigurableExtensionInterface if you plan to define new configuration options - you don’t need this if you’re only reading existing options.

+ +

Reading Configuration Values

+ +

Okay, so your extension has defined the different options that are available, but now you want to start using them within your custom extension. There are a few ways you can access the values:

+ +

During Extension Registration

+ +

Perhaps your extension needs to decide whether/how to register certain parsers/renderers/etc based on the user-provided configuration values - in that case, you can read the value from the $environment - for example:

+ +
use League\Config\ConfigurationBuilderInterface;
+use League\CommonMark\Environment\EnvironmentBuilderInterface;
+use League\CommonMark\Extension\ConfigurableExtensionInterface;
+
+final class MyCustomExtension implements ConfigurableExtensionInterface
+{
+    public function configureSchema(ConfigurationBuilderInterface $builder): void
+    {
+        // (see code example above)
+    }
+
+    public function register(EnvironmentBuilderInterface $environment): void
+    {
+        if ($environment->getConfiguration()->get('my_extension/enable_some_feature')) {
+            $environment->addBlockStartParser(new MyCustomParser());
+            $environment->addRenderer(MyCustomBlockType::class, new MyCustomRenderer());
+        }
+    }
+}
+
+ +

Within Parsers/Renderers/Listeners

+ +

Perhaps you want to reference those configuration values from within a custom parser, renderer, event listener, or something else. This can easily by done by having that class also implement ConfigurationAwareInterface. This interface signals to the Environment that your class needs a copy of the final configuration so it can read it later:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\Config\ConfigurationAwareInterface;
+use League\Config\ConfigurationInterface;
+
+final class MyCustomRenderer implements NodeRendererInterface, ConfigurationAwareInterface
+{
+    /**
+     * @var ConfigurationInterface
+     */
+    private $config;
+
+    public function setConfiguration(ConfigurationInterface $configuration): void
+    {
+        $this->config = $configuration;
+    }
+
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return 'My favorite number is ' . $this->config->get('my_extension/favorite_number');
+    }
+}
+
+ +

You can access any configuration value from here, not just the ones you might have defined yourself.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/cursor/index.html b/2.5/customization/cursor/index.html new file mode 100644 index 0000000000..3c2869a342 --- /dev/null +++ b/2.5/customization/cursor/index.html @@ -0,0 +1,545 @@ + + + + + + + + + + + + + + + + + Cursor - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Cursor

+ +

A Cursor is essentially a fancy string wrapper that remembers your current position as you parse it. It contains a set of highly-optimized methods making it easy to parse characters, match regular expressions, and more.

+ +

Supported Encodings

+ +

As of now, only UTF-8 (and, by extension, ASCII) encoding is supported.

+ +

Usage

+ +

Instantiating a new Cursor is as simple as:

+ +
use League\CommonMark\Parser\Cursor;
+
+$cursor = new Cursor('Hello World!');
+
+ +

Or, if you’re creating a custom block parser or inline parser, a pre-configured Cursor will be provided to you with (with the Cursor already set to the current position trying to be parsed).

+ +

Methods

+ +

You can then call any of the following methods to parse the string within that Cursor:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
MethodPurpose
getPosition()Returns the current position/index of the Cursor within the string
getColumn()Returns the current column (used when handling tabbed indentation)
getIndent()Returns the current amount of indentation
isIndented()Returns whether the cursor is indented to INDENT_LEVEL
getCharacter(int $index)Returns the character at the given absolute position
getCurrentCharacter()Returns the character at the current position
peek()Returns the next character without changing the current position of the cursor
peek(int $offset)Returns the character $offset chars away without changing the current position of the cursor
getNextNonSpacePosition()Returns the position of the next character which is not a space or tab
getNextNonSpaceCharacter()Returns the next character which isn’t a space (or tab)
advance()Moves the cursor forward by 1 character
advanceBy(int $characters)Moves the cursor forward by $characters characters
advanceBy(int $characters, true)Moves the cursor forward by $characters characters, handling tabs as columns
advanceBySpaceOrTab()Advances forward one character (and returns true) if it’s a space or tab; returns false otherwise
advanceToNextNonSpaceOrTab()Advances forward past all spaces and tabs found, returning the number of such characters found
advanceToNextNonSpaceOrNewline()Advances forward past all spaces and newlines found, returning the number of such characters found
advanceToEnd()Advances the position to the very end of the string, returning the number of such characters passed
match(string $regex)Attempts to match the given $regex; returns null if matching fails, otherwise it advances past and returns the matched text
getPreviousText()Returns the text that was just advanced through during the last advance__() or match() operation
getRemainder()Returns the contents of the string from the current position through the end of the string
isBlank()Returns whether the remainder is blank (we’re at the end or only space characters remain)
isAtEnd()Returns whether the cursor has reached the end of the string
saveState()Encapsulates the current state of the cursor into an array in case you need to restoreState() later
restoreState($state)Pass the result of saveState() back into here to restore the original state of the Cursor
getLine()Returns the entire string (not taking the position into account)
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/delimiter-processing/index.html b/2.5/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..ecc9c5acd0 --- /dev/null +++ b/2.5/customization/delimiter-processing/index.html @@ -0,0 +1,504 @@ + + + + + + + + + + + + + + + + + Delimiter Processing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Delimiter Processing

+ +

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

+ +

Delimiter runs are a special type of inline:

+ + + +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

When implementing something with these characteristics you should consider leveraging delimiter runs; otherwise, a basic inline parser should be sufficient.

+ +

Delimiter Priority

+ +

Delimiter processors have a lower priority than inline parsers - if an inline parser successfully handles the same special character you’re interested in then your delimiter processor will not be called.

+ +

Implementing Standalone Delimiter Processors

+ +

Implement the DelimiterProcessorInterface and add it to your environment:

+ +
$environment->addDelimiterProcessor(new MyCustomDelimiterProcessor());
+
+ +

getOpeningCharacter() and getClosingCharacter()

+ +

These two methods tell the engine which characters are used to delineate your custom syntax. Generally these will be the same, such as when using *emphasis*, but they can be different; for example, maybe you want to use {this syntax}. Simply tell the engine which characters you’d like to use.

+ +

getMinimumLength()

+ +

This method tells the engine the minimum number of characters needed to match or “activate” your processor. For example, if you want to match {{example}} and not {example}, set this to 2.

+ +

getDelimiterUse()

+ +
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int;
+
+ +

This method is used to tell the engine how many characters from the matching delimiters should be consumed. For simple processors you’ll likely return 1 (or whatever your minimum length is). In more advanced cases, you can examine the opening and closing delimiters and perform additional logic to determine whether they should be fully or partially consumed. You can also return 0 if you’d like.

+ +

process()

+ +
public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void;
+
+ +

This is where the magic happens. Once the engine determines it can use the delimiter it found (by looking at all the other methods above) it’ll call this method. Your job is to take everything between the $opener and $closer and wrap that in whatever custom inline element you’d like. Here’s a basic example of wrapping the inner contents inside a new Emphasis element:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Emphasis;
+
+// Create the outer element
+$emphasis = new Emphasis();
+
+// Add everything between $opener and $closer (exclusive) to the new outer element
+$tmp = $opener->next();
+while ($tmp !== null && $tmp !== $closer) {
+    $next = $tmp->next();
+    $emphasis->appendChild($tmp);
+    $tmp = $next;
+}
+
+// Place the outer element into the AST
+$opener->insertAfter($emphasis);
+
+ +

Note that $opener and $closer will be automatically removed for you after this function returns - no need to do that yourself.

+ +

Combining Inline Parsers with Delimiter Processors

+ +

Basic delimiter processors, as covered above, do not require any custom inline parsers - they’ll “just work”. But in some rare cases you may want to pair it with a custom inline parser: the inline parser will identify the delimiter, adding an entry to the delimiter stack for the processor to process later. Note that this is an advanced use case and you probably don’t need this. But if you do then read on.

+ +

Inline Parsers and the Delimiter Stack

+ +

As your identifies potential delimiter-based inlines, it should create a new AbstractStringContainer node (either Text or something custom) with the inner contents and also push a new DelimiterInterface onto the DelimiterStack:

+ +
use League\CommonMark\Delimiter\Delimiter;
+use League\CommonMark\Node\Inline\Text;
+
+$node = new Text($cursor->getPreviousText(), [
+    'delim' => true,
+]);
+$inlineContext->getContainer()->appendChild($node);
+
+// Add entry to stack to this opener
+$delimiter = new Delimiter($character, $numDelims, $node, $canOpen, $canClose);
+$inlineContext->getDelimiterStack()->push($delimiter);
+
+ +

This basically tells the engine that text was found which might be emphasis, but due to the delimiter run rules we can’t make that determination just yet. That final determination is later on by a “delimiter processor”.

+ +

Your implementation of the delimiter processor won’t look any different in this approach - you’ll still need to implement all of the same methods especially process(). The difference is that you’ve identified where the delimiter is, instead of relying on the engine to do this for you.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/disabling-features/index.html b/2.5/customization/disabling-features/index.html new file mode 100644 index 0000000000..d43fbab1b6 --- /dev/null +++ b/2.5/customization/disabling-features/index.html @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + Disabling Features - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Disabling Features

+ +

The CommonMark parser is designed to be highly configurable. You can disable certain features that you don’t want to have in your application. There are a few ways to do this, depending on your needs:

+ +

Avoiding Parsing

+ +

You cannot disable an already-registered parser, but you can prevent it from being registered with +the Environment in the first place. This is exactly how the +InlinesOnlyExtension works - it’s a copy of the CommonMarkCoreExtension class but +with the parsers we don’t want removed.

+ +

You can mirror this approach by defining your own custom extension class that registers +only the specific parsers, renderers, etc. that you want.

+ +

The only potential downside to this approach is that any syntax for those disabled features will appear in the output. +For example, if you were to prevent block quotes from being parsed, then the following Markdown:

+ +
> This is a block quote
+
+ +

Would have the > character appear in the output HTML:

+ +
<p>&gt; This is a block quote</p>
+
+ +

This is probably fine for most use cases.

+ +

Removing Parsed Elements

+ +

An alternative approach is to keep the parser enabled, but remove the parsed elements from the AST before rendering.

+ +

You’d create an event listener +(sort of like this one) that will +iterate all parsed elements, locate the target nodes, and remove them +by calling $node->detach().

+ +

There are three potential advantages to this approach:

+ +
    +
  1. You don’t need to create a custom extension class or prevent parsers from being registered
  2. +
  3. You can selectively remove certain elements based on their properties (e.g. only remove heading levels 3-6) while keeping others
  4. +
  5. The syntax and contents of the removed elements will not appear in the output HTML
  6. +
+ +

The downside is that you still incur the overhead of parsing the elements that are eventually removed.

+ +

Override Rendering

+ +

The final approach is to keep the parser enabled, but override how the parsed elements are rendered. For example, +you could implement a custom renderer for certain elements that simply returns +something else (perhaps an empty string, or an HTML comment of <!-- REMOVED -->) instead of the HTML you don’t want.

+ +

This approach is not recommended because:

+ +
    +
  1. You still incur the overhead of parsing the elements that are eventually removed
  2. +
  3. You’d need to register your custom renderer with a higher priority than the default renderer
  4. +
  5. You’d need to repeat this for every renderer that could potentially render the elements you want to remove
  6. +
+ +

It should technically work though, if you really want to go this route.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/environment/index.html b/2.5/customization/environment/index.html new file mode 100644 index 0000000000..af9046a602 --- /dev/null +++ b/2.5/customization/environment/index.html @@ -0,0 +1,506 @@ + + + + + + + + + + + + + + + + + The Environment - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

The Environment

+ +

The Environment contains all of the parsers, renderers, configurations, etc. that the library uses during the conversion process. You therefore must register all extensions, parsers, renderers, etc. with the Environment so that the library is aware of them.

+ +

An empty Environment can be obtained like this:

+ +
use League\CommonMark\Environment\Environment;
+
+$config = [];
+$environment = new Environment($config);
+
+ +

You can customize the Environment using any of the methods below (from the EnvironmentBuilderInterface interface).

+ +

Once your Environment is configured with whatever configuration and extensions you want, you can instantiate a MarkdownConverter and start converting MD to HTML:

+ +
use League\CommonMark\MarkdownConverter;
+
+// Using $environment from the previous code sample
+$converter = new MarkdownConverter($environment);
+
+echo $converter->convert('# Hello World!');
+
+ +

addExtension()

+ +
public function addExtension(ExtensionInterface $extension);
+
+ +

Registers the given extension with the environment. For example, if you want core CommonMark functionality plus footnote support:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+
+$config = [];
+$environment = new Environment($config);
+
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new FootnoteExtension());
+
+ +

addBlockStartParser()

+ +
public function addBlockStartParser(BlockStartParserInterface $parser, int $priority = 0);
+
+ +

Registers the given BlockStartParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Block Parsing for details.

+ +

addInlineParser()

+ +
public function addInlineParser(InlineParserInterface $parser, int $priority = 0);
+
+ +

Registers the given InlineParserInterface with the environment with the given priority (a higher number will be executed earlier).

+ +

See Inline Parsing for details.

+ +

addDelimiterProcessor()

+ +
public function addDelimiterProcessor(DelimiterProcessorInterface $processor);
+
+ +

Registers the given DelimiterProcessorInterface with the environment.

+ +

See Inline Parsing for details.

+ +

addRenderer()

+ +
public function addRenderer(string $nodeClass, NodeRendererInterface $renderer, int $priority = 0);
+
+ +

Registers a NodeRendererInterface to handle a specific type of AST node ($nodeClass) with the given priority (a higher number will be executed earlier).

+ +

See Rendering for details.

+ +

addEventListener()

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0);
+
+ +

Registers the given event listener with the environment.

+ +

See Event Dispatcher for details.

+ +

Priority

+ +

Several of these methods allows you to specify a numeric $priority. In cases where multiple things are registered, the internal engine will attempt to use the higher-priority ones first, falling back to lower priority ones if the first one(s) were unable to handle things.

+ +

Accessing the Environment and Configuration within parsers/renderers/etc

+ +

If your custom parser/renderer/listener/etc. implements either EnvironmentAwareInterface or ConfigurationAwareInterface we’ll automatically inject the environment or configuration into them once the environment has been fully initialized. This will provide your code with access to the finalized information it may need.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/event-dispatcher/index.html b/2.5/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..6fe21ae1e6 --- /dev/null +++ b/2.5/customization/event-dispatcher/index.html @@ -0,0 +1,580 @@ + + + + + + + + + + + + + + + + + Event Dispatcher - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Event Dispatcher

+ +

This library includes basic, PSR-14-compliant event dispatcher functionality. This makes it possible to add hook points throughout the library and third-party extensions which other code can listen for and execute code.

+ +

Event Class

+ +

Any PSR-14 compliant event can be used, though we also provide an AbstractEvent class you can use to easily create your own events:

+ +
use League\CommonMark\Event\AbstractEvent;
+
+class MyCustomEvent extends AbstractEvent {}
+
+ +

An event can have any number of methods on it which return useful information the listeners can use or modify.

+ +

Registering Listeners

+ +

Listeners can be registered with the Environment using the addEventListener() method:

+ +
public function addEventListener(string $eventClass, callable $listener, int $priority = 0)
+
+ +

The parameters for this method are:

+ +
    +
  1. The fully-qualified name of the event class you wish to observe
  2. +
  3. Any PHP callable to execute when that type of event is dispatched
  4. +
  5. An optional priority (defaults to 0)
  6. +
+ +

For example:

+ +
// Telling the environment which method to call:
+$customListener = new MyCustomListener();
+$environment->addEventListener(MyCustomEvent::class, [$customListener, 'onDocumentParsed']);
+
+// Or if MyCustomerListener has an __invoke() method:
+$environment->addEventListener(MyCustomEvent::class, new MyCustomListener(), 10);
+
+// Or use any other type of callable you wish!
+$environment->addEventListener(MyCustomEvent::class, function (MyCustomEvent $event) {
+    // TODO: Stuff
+}, 10);
+
+ +

Dispatching Events

+ +

Events can be dispatched via the $environment->dispatch() method which takes a single argument - the event object to dispatch:

+ +
$environment->dispatch(new MyCustomEvent());
+
+ +

Listeners will be called in order of priority (higher priorities will be called first). If multiple listeners have the same priority, they’ll be called in the order in which they were registered. If you’d like your listener to prevent other subsequent events from running, simply call $event->stopPropagation().

+ +

Listeners may call any method on the event to get more information about the event, make changes to event data, etc.

+ +

List of Available Events

+ +

This library supports the following default events which you can register listeners for:

+ +

League\CommonMark\Event\DocumentPreParsedEvent

+ +

This event is dispatched just before any processing is done. It can be used to pre-populate reference map of a document or manipulate the Markdown contents before any processing is performed.

+ +

League\CommonMark\Event\DocumentParsedEvent

+ +

This event is dispatched once all other processing is done. This offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering.

+ +

League\CommonMark\Event\DocumentPreRenderEvent

+ +

This event is dispatched by the renderer just before rendering begins. Like with DocumentParsedEvent, this offers extensions the opportunity to inspect and modify the Abstract Syntax Tree prior to rendering, but with the added knowledge of which format is being rendered to (e.g. html).

+ +

League\CommonMark\Event\DocumentRenderedEvent

+ +

This event is dispatched once the rendering step has been completed, just before the output is returned. The final output can be adjusted at this point or additional metadata can be attached to the return object.

+ +

Bring Your Own PSR-14 Event Dispatcher

+ +

Although this library provides PSR-14 compliant event dispatching out-of-the-box, you may want to use your own PSR-14 event dispatcher instead. This is possible as long as that third-party library both:

+ +
    +
  1. Implements the PSR-14 EventDispatcherInterface; and,
  2. +
  3. Allows you to register additional ListenerProviderInterface instances with that dispatcher library
  4. +
+ +

Not all libraries support this so please check carefully! Assuming yours does, delegating all the event behavior to that library can be done with two steps:

+ +

First, call the setEventDispatcher() method on the Environment to register that other implementation. With that done, any calls to Environment::dispatch() will be passed through to that other dispatcher. But we still need to let that dispatcher know about the events registered by CommonMark extensions, otherwise nothing will happen when events are dispatched.

+ +

Because the Environment implements PSR-14’s ListenerProviderInterface you’ll also need to pass the configured Environment object to your event dispatcher so that it becomes aware of those available events.

+ +

Example

+ +

Here’s an example of a listener which uses the DocumentParsedEvent to add an external-link class to external URLs:

+ +
use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Event\DocumentParsedEvent;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+
+class ExternalLinkProcessor
+{
+    private $environment;
+
+    public function __construct(EnvironmentInterface $environment)
+    {
+        $this->environment = $environment;
+    }
+
+    public function onDocumentParsed(DocumentParsedEvent $event): void
+    {
+        $document = $event->getDocument();
+        $walker = $document->walker();
+        while ($event = $walker->next()) {
+            $node = $event->getNode();
+
+            // Only stop at Link nodes when we first encounter them
+            if (!($node instanceof Link) || !$event->isEntering()) {
+                continue;
+            }
+
+            $url = $node->getUrl();
+            if ($this->isUrlExternal($url)) {
+                $node->data->append('attributes/class', 'external-link');
+            }
+        }
+    }
+
+    private function isUrlExternal(string $url): bool
+    {
+        // Only look at http and https URLs
+        if (!preg_match('/^https?:\/\//', $url)) {
+            return false;
+        }
+
+        $host = parse_url($url, PHP_URL_HOST);
+
+        return $host != $this->environment->getConfiguration()->get('host');
+    }
+}
+
+ +

And here’s how you’d use it:

+ +
use League\CommonMark\CommonMarkConverter;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Event\DocumentParsedEvent;
+
+$env = new Environment();
+
+$listener = new ExternalLinkProcessor($env);
+$env->addEventListener(DocumentParsedEvent::class, [$listener, 'onDocumentParsed']);
+
+$converter = new CommonMarkConverter(['host' => 'commonmark.thephpleague.com'], $env);
+
+$input = 'My two favorite sites are <https://google.com> and <https://commonmark.thephpleague.com>';
+
+echo $converter->convert($input);
+
+ +

Output (formatted for readability):

+ +
<p>
+    My two favorite sites are
+    <a class="external-link" href="https://google.com">https://google.com</a>
+    and
+    <a href="https://commonmark.thephpleague.com">https://commonmark.thephpleague.com</a>
+</p>
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/extensions/index.html b/2.5/customization/extensions/index.html new file mode 100644 index 0000000000..0bb237b5db --- /dev/null +++ b/2.5/customization/extensions/index.html @@ -0,0 +1,447 @@ + + + + + + + + + + + + + + + + + Extensions - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Extensions

+ +

Extensions provide a way to group related parsers, renderers, etc. together with pre-defined priorities, configuration settings, etc. They are perfect for distributing your customizations as reusable, open-source packages that others can plug into their own projects!

+ +

To create an extension, simply create a new class implementing ExtensionInterface. This has a single method where you’re given a ConfigurableEnvironmentInterface to register whatever things you need to. For example:

+ +
use League\CommonMark\Extension\ExtensionInterface;
+use League\CommonMark\Environment\ConfigurableEnvironmentInterface;
+
+final class EmojiExtension implements ExtensionInterface
+{
+    public function register(ConfigurableEnvironmentInterface $environment): void
+    {
+        $environment
+            // TODO: Create the EmojiParser, Emoji, and EmojiRenderer classes
+            ->addInlineParser(new EmojiParser(), 20)
+            ->addInlineRenderer(Emoji::class, new EmojiRenderer(), 0)
+        ;
+    }
+}
+
+ +

To hook up your new extension to the Environment, simply do this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new EmojiExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello! :wave:');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/inline-parsing/index.html b/2.5/customization/inline-parsing/index.html new file mode 100644 index 0000000000..713c076c0e --- /dev/null +++ b/2.5/customization/inline-parsing/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + Inline Parsing - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Inline Parsing

+ +

There are two ways to implement custom inline syntax:

+ + + +

The difference between normal inlines and delimiter-run-based inlines is subtle but important to understand. In a nutshell, delimiter-run-based inlines:

+ + + +

An example of this would be emphasis:

+ +
This is an example of **emphasis**. Note how the text is *wrapped* with the same character(s) before and after.
+
+ +

If your syntax looks like that, consider using a delimiter processor instead. Otherwise, an inline parser is your best bet.

+ +

Implementing Inline Parsers

+ +

Inline parsers should implement InlineParserInterface and the following two methods:

+ +

getMatchDefinition()

+ +

This method should return an instance of InlineParserMatch which defines the text the parser is looking for. Examples of this might be something like:

+ +
use League\CommonMark\Parser\Inline\InlineParserMatch;
+
+InlineParserMatch::string('@');                  // Match any '@' characters found in the text
+InlineParserMatch::string('foo');                // Match the text 'foo' (case insensitive)
+
+InlineParserMatch::oneOf('@', '!');              // Match either character
+InlineParserMatch::oneOf('http://', 'https://'); // Match either string
+
+InlineParserMatch::regex('\d+');                 // Match the regular expression (omit the regex delimiters and any flags)
+
+ +

Once a match is found, the parse() method below may be called.

+ +

parse()

+ +

This method will be called if both conditions are met:

+ +
    +
  1. The engine has found at a matching string in the current line; and,
  2. +
  3. No other inline parsers with a higher priority have successfully parsed the text at this point in the line
  4. +
+ +

Parameters

+ + + +
InlineParserContext
+ +

This class has several useful methods:

+ + + +

Return value

+ +

parse() should return false if it’s unable to handle the text at the current position for any reason. Other parsers will then have a chance to try parsing that text. If all registered parsers return false, the text will be added as plain text.

+ +

Returning true tells the engine that you’ve successfully parsed the character (and related ones after it). It is your responsibility to:

+ +
    +
  1. Advance the cursor to the end of the parsed/matched text
  2. +
  3. Add the parsed inline to the container ($inlineContext->getContainer()->appendChild(...))
  4. +
+ +

Inline Parser Examples

+ +

Example 1 - Twitter Handles

+ +

Let’s say you wanted to autolink Twitter handles without using the link syntax. This could be accomplished by registering a new inline parser to handle the @ character:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class TwitterHandleParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::regex('@([A-Za-z0-9_]{1,15}(?!\w))');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+        // The @ symbol must not have any other characters immediately prior
+        $previousChar = $cursor->peek(-1);
+        if ($previousChar !== null && $previousChar !== ' ') {
+            // peek() doesn't modify the cursor, so no need to restore state first
+            return false;
+        }
+
+        // This seems to be a valid match
+        // Advance the cursor to the end of the match
+        $cursor->advanceBy($inlineContext->getFullMatchLength());
+
+        // Grab the Twitter handle
+        [$handle] = $inlineContext->getSubMatches();
+        $profileUrl = 'https://twitter.com/' . $handle;
+        $inlineContext->getContainer()->appendChild(new Link($profileUrl, '@' . $handle));
+        return true;
+    }
+}
+
+// And here's how to hook it up:
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new TwitterHandleParser());
+
+ +

Example 2 - Emoticons

+ +

Let’s say you want to automatically convert smilies (or “frownies”) to emoticon images. This is incredibly easy with an inline parser:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Image;
+use League\CommonMark\Parser\Inline\InlineParserInterface;
+use League\CommonMark\Parser\Inline\InlineParserMatch;
+use League\CommonMark\Parser\InlineParserContext;
+
+class SmilieParser implements InlineParserInterface
+{
+    public function getMatchDefinition(): InlineParserMatch
+    {
+        return InlineParserMatch::oneOf(':)', ':(');
+    }
+
+    public function parse(InlineParserContext $inlineContext): bool
+    {
+        $cursor = $inlineContext->getCursor();
+
+        // Advance the cursor past the 2 matched chars since we're able to parse them successfully
+        $cursor->advanceBy(2);
+
+        // Add the corresponding image
+        if ($inlineContext->getFullMatch() === ':)') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/happy.png'));
+        } elseif ($inlineContext->getFullMatch() === ':(') {
+            $inlineContext->getContainer()->appendChild(new Image('/img/sad.png'));
+        }
+
+        return true;
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addInlineParser(new SmilieParserParser());
+
+ +

Tips

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/overview/index.html b/2.5/customization/overview/index.html new file mode 100644 index 0000000000..3653151522 --- /dev/null +++ b/2.5/customization/overview/index.html @@ -0,0 +1,485 @@ + + + + + + + + + + + + + + + + + Customization Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Customization Overview

+ +

Ready to go beyond the basics of converting Markdown to HTML? This page describes some of the more advanced things you can customize this library to do.

+ +

Parsing and Rendering

+ +

The actual process of converting Markdown to HTML has several steps:

+ +
    +
  1. Create an Environment, adding whichever extensions/parser/renders/configuration you need
  2. +
  3. Instantiate a MarkdownParser and HtmlRenderer using that Environment
  4. +
  5. Use the MarkdownParser to parse the Markdown input into an Abstract Syntax Tree (aka an “AST”)
  6. +
  7. Use the HtmlRenderer to convert the AST Document into HTML
  8. +
+ +

The MarkdownConverter class handles all of this for you, but you can execute that process yourself if you wish:

+ +
use League\CommonMark\Parser\MarkdownParser;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Renderer\HtmlRenderer;
+
+$environment = new Environment([
+    'html_input' => 'strip',
+]);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$parser = new MarkdownParser($environment);
+$htmlRenderer = new HtmlRenderer($environment);
+
+$markdown = '# Hello World!';
+
+$document = $parser->parse($markdown);
+echo $htmlRenderer->renderDocument($document);
+
+// <h1>Hello World!</h1>
+
+ +

Feel free to swap out different components or add your own steps in between. However, the best way to customize this library is to create your own extensions which hook into the parsing and rendering steps - continue reading to see which kinds of extension points are available to you.

+ +

Add Custom Syntax with Parsers

+ +

Parsers examine the Markdown input and produce an abstract syntax tree (AST) of the document’s structure. +This resulting AST contains both blocks (structural elements like paragraphs, lists, headers, etc) and inlines (words, spaces, links, emphasis, etc).

+ +

There are two main types of parsers:

+ + + +

The parsing approach is identical for both types - examine text at the current position (via the Cursor) and determine if you can handle it; +if so, create the corresponding AST element, +otherwise you abort and the engine will try other parsers. If no parser succeeds then the current text is treated as plain text.

+ +

Simple delimiter-based inlines (like emphasis, strikethrough, etc.) can be parsed without needing a dedicated inline parser by leveraging the new Delimiter Processing functionality.

+ +

AST manipulation

+ +

Once the Abstract Syntax Tree is parsed, you are free to access/manipulate it as needed before it’s passed into the rendering engine.

+ +

Customize HTML Output with Custom Renderers

+ +

Renderers convert the parsed blocks/inlines from the AST representation into HTML. When registering these with the environment, you must tell it which block/inline classes it should handle. This allows you to essentially “swap out” built-in renderers with your own.

+ +

Examples

+ +

Some examples of what’s possible:

+ + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/rendering/index.html b/2.5/customization/rendering/index.html new file mode 100644 index 0000000000..4f1672a047 --- /dev/null +++ b/2.5/customization/rendering/index.html @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Custom Rendering

+ +

Renderers are responsible for converting the parsed AST elements into their HTML representation.

+ +

All block renderers should implement NodeRendererInterface and its render() method. Note that in v2.0, both +block renderers and inline renderers share the same interface and method:

+ +

render()

+ +
public function render(Node $node, ChildNodeRendererInterface $childRenderer);
+
+ +

The HtmlRenderer will call this method during the rendering process whenever a supported element is encountered.

+ +

If your renderer can only handle certain block types, be sure to verify that you’ve been passed the correct type.

+ +

Parameters

+ + + +

Return value

+ +

The method must return the final HTML representation of the node and its contents, including any children. This can be an HtmlElement object (preferred; castable to a string), a string of raw HTML, or null if it could not render (and perhaps another renderer should give it a try).

+ +

If you choose to return an HTML string you are responsible for handling any escaping that may be necessary.

+ +

HtmlElement

+ +

Instead of manually building the HTML output yourself, you can leverage the HtmlElement to generate that for you. For example:

+ +
use League\CommonMark\Util\HtmlElement;
+
+$link = new HtmlElement('a', ['href' => 'https://github.com'], 'GitHub');
+$img = new HtmlElement('img', ['src' => 'logo.jpg'], '', true);
+
+ +

Designating Renderers

+ +

When registering your renderer, you must tell the Environment which node element class your renderer should handle. For example:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// First param - the node class type that should use our renderer
+// Second param - instance of the renderer
+$environment->addRenderer(FencedCode::class, new MyCustomCodeRenderer());
+
+ +

A single renderer could even be used for multiple types:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\FencedCode;
+use League\CommonMark\Extension\CommonMark\Node\Block\IndentedCode;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$myRenderer = new MyCustomCodeRenderer();
+
+$environment->addRenderer(FencedCode::class, $myRenderer, 10);
+$environment->addRenderer(IndentedCode::class, $myRenderer, 20);
+
+ +

Multiple renderers can be added per element type - when this happens, we use the result from the highest-priority renderer that returns a non-null result.

+ +

Example

+ +

Here’s a custom renderer which renders thematic breaks as text (instead of <hr>):

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\ThematicBreak;
+use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class TextDividerRenderer implements NodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+}
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(ThematicBreak::class, new TextDividerRenderer());
+
+ +

Note that thematic breaks should not contain children, which is why the $childRenderer is unused in this example. Otherwise we’d have to call code like this and return the result as part of the rendered HTML we’re generating here: $innerHtml = $childRenderer->renderNodes($node->children());

+ +

Tips

+ + + +

Wrapping Elements with HtmlDecorator

+ +

A utility class called HtmlDecorator is provided to make it easier to wrap the output of any renderer within an additional HTML tag with custom attributes and/or classes. To use it:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Renderer\HtmlDecorator;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\Extension\Table\TableRenderer;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addRenderer(Table::class, new HtmlDecorator(new TableRenderer(), 'div', ['class' => 'table-responsive']));
+
+ +

XML Rendering

+ +

The XML renderer will automatically attempt to convert any AST nodes to XML by inspecting the name of the block/inline node and its attributes. You can instead control the XML element name and attributes by making your renderer implement XmlNodeRendererInterface:

+ +
use League\CommonMark\Node\Node;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+use League\CommonMark\Xml\XmlNodeRendererInterface;
+
+class TextDividerRenderer implements NodeRendererInterface, XmlNodeRendererInterface
+{
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        return new HtmlElement('pre', ['class' => 'divider'], '==============================');
+    }
+
+    public function getXmlTagName(Node $node): string
+    {
+        return 'text_divider';
+    }
+
+    public function getXmlAttributes(Node $node): array
+    {
+        return ['character' => '='];
+    }
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/customization/slug-normalizer/index.html b/2.5/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..9035caa30f --- /dev/null +++ b/2.5/customization/slug-normalizer/index.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + Slug Normalizer - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Slug Normalizer

+ +

“Slugs” are strings used within href, name, and id HTML attributes to identify particular elements within a document.

+ +

Some extensions (like the HeadingPermalinkExtension) need the ability to convert user-provided text into these URL-safe slugs while also ensuring that these are unique throughout the generated HTML. The Environment provides a pre-built normalizer you can use for this purpose.

+ +

Usage

+ +

You can obtain a reference to the built-in slug normalizer by calling $environment->getSlugNormalizer();

+ +

To use this within your extension, have your parser/renderer/whatever implement EnvironmentAwareInterface and then implement the corresponding setEnvironment method like this:

+ +

+use League\CommonMark\Environment\EnvironmentInterface;
+use League\CommonMark\Environment\EnvironmentAwareInterface;
+
+class MyCustomParserOrRenderer implements EnvironmentAwareInterface
+{
+    private $slugNormalizer;
+
+    public function setEnvironment(EnvironmentInterface $environment): void
+    {
+        $this->slugNormalizer = $environment->getSlugNormalizer();
+    }
+}
+
+ +

You can then call $this->slugNormalizer->normalize($text) as needed.

+ +

Configuration

+ +

The slug_normalizer configuration section allows you to adjust the following options:

+ +

instance

+ +

You can change the string that is used as the “slug” by setting the instance option to any class that implements TextNormalizerInterface. +We provide a simple SlugNormalizer by default, but you may want to plug in a different library or create your own normalizer instead.

+ +

For example, if you’d like each slug to be an MD5 hash, you could create a class like this:

+ +
use League\CommonMark\Normalizer\TextNormalizerInterface;
+
+final class MD5Normalizer implements TextNormalizerInterface
+{
+    public function normalize(string $text, $context = null): string
+    {
+        return md5($text);
+    }
+}
+
+ +

And then configure it like this:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new MD5Normalizer(),
+    ],
+];
+
+ +

Or you could use PHP’s anonymous class feature to define the generator’s behavior without creating a new class file:

+ +
$config = [
+    'slug_normalizer' => [
+        // ... other options here ...
+        'instance' => new class implements TextNormalizerInterface {
+            public function normalize(string $text, $context = null): string
+            {
+                // TODO: Implement your code here
+            }
+        },
+    ],
+];
+
+ +

max_length

+ +

This can be configured to limit the length of that slug to prevent overly-long values. By default, that limit is 255 characters. You may set this to any positive integer, or 0 for no limit.

+ +

(Note that generated slugs might be slightly longer than this “limit” if the unique option is enabled and the slug generator detects a duplicate slug and needs to add a suffix to make it unique.)

+ +

unique

+ +

This options controls whether slugs should be unique. Possible values include:

+ + + +

You might have a use case where you’re converting several different Markdown documents on the same page and so you’d like to ensure that none of those documents use conflicting slugs. In that case, you should set the scope option to 'environment' to ensure that a single instance of a MarkdownConverter (which uses a single Environment) will never produce the same slug twice during its lifetime (which usually lasts the entire duration of a single HTTP request).

+ +

If you need complete control over how unique slugs are generated, make your 'instance' implement UniqueSlugNormalizerInterface; otherwise, we’ll simply append incremental numbers to slugs to ensure they are unique.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/attributes/index.html b/2.5/extensions/attributes/index.html new file mode 100644 index 0000000000..3bff8103e7 --- /dev/null +++ b/2.5/extensions/attributes/index.html @@ -0,0 +1,501 @@ + + + + + + + + + + + + + + + + + Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Attributes

+ +

The AttributesExtension allows HTML attributes to be added from within the document.

+ +

Attribute Syntax

+ +

The basic syntax was inspired by Kramdown’s Attribute Lists feature.

+ +

You can assign any attribute to a block-level element. Just directly prepend or follow the block with a block inline attribute list. +That consists of a left curly brace, optionally followed by a colon, the attribute definitions and a right curly brace:

+ +
> A nice blockquote
+{: title="Blockquote title"}
+
+ +

This results in the following output:

+ +
<blockquote title="Blockquote title">
+<p>A nice blockquote</p>
+</blockquote>
+
+ +

CSS-selector-style declarations can be used to set the id and class attributes:

+ +
{#id .class}
+## Header
+
+ +

Output:

+ +
<h2 class="class" id="id">Header</h2>
+
+ +

As with a block-level element you can assign any attribute to a span-level elements using a span inline attribute list, +that has the same syntax and must immediately follow the span-level element:

+ +
This is *red*{style="color: red"}.
+
+ +

Output:

+ +
<p>This is <em style="color: red">red</em>.</p>
+
+ +

Empty-Value Attributes

+ +

Attributes can be rendered in HTML without a value by using true value in the markdown document:

+ +
{itemscope=true}
+## Header
+
+ +

Output:

+ +
<h2 itemscope>Header</h2>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Attributes\AttributesExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/autolinks/index.html b/2.5/extensions/autolinks/index.html new file mode 100644 index 0000000000..5d74f2894a --- /dev/null +++ b/2.5/extensions/autolinks/index.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + + + + + + Autolink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Autolink Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The AutolinkExtension adds GFM-style autolinking. It automatically links URLs and email addresses even when the CommonMark <...> autolink syntax is not used.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the AutolinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'autolink' => [
+        'allowed_protocols' => ['https'], // defaults to ['https', 'http', 'ftp']
+        'default_protocol' => 'https', // defaults to 'http'
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new AutolinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the https://github.com/thephpleague/commonmark project with the Autolink extension!');
+
+ +

Configuration

+ +

As of version 2.5.0, this extension supports the following configuration options under the autolink configuration:

+ +

allowed_protocols option

+ +

This option defines which types of URLs will be autolinked. The default value of ['https', 'http', 'ftp'] means that only URLs using those protocols will be autolinked. Setting this to just ['https'] means that only HTTPS URLs will be autolinked.

+ +

default_protocol option

+ +

This option defines the default protocol for URLs that start with www. and don’t have an explicit protocol set. For example, setting this to https would convert www.example.com to https://www.example.com.

+ +

@mention-style Autolinking

+ +

As of v1.5, mention autolinking is now handled by a Mention Parser outside of this extension.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/commonmark/index.html b/2.5/extensions/commonmark/index.html new file mode 100644 index 0000000000..d075f5d732 --- /dev/null +++ b/2.5/extensions/commonmark/index.html @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + CommonMark Core Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

CommonMark Core Extension

+ +

The CommonMarkCoreExtension class contains all of the core Markdown syntax - things like parsing headers, code blocks, links, image, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Included by Default

+ +

This extension is automatically installed for you (behind-the-scenes) whenever you instantiate the parser using the CommonMarkConverter class:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+ +

Manual Usage

+ +

If you ever create a new Environment() from scratch, you’ll probably want to include the CommonMarkCoreExtension() so you get all the standard Markdown syntax included:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new Environment with the core extension
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Alternatively, if you don’t want all of the core Markdown syntax, avoid using CommonMarkCoreExtension. You can always add just the individual parsers, renderers, etc. you actually want with the Environment. (This is actually how the Inlines Only Extension works - it only includes a subset of things that CommonMarkCoreExtension does!)

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/default-attributes/index.html b/2.5/extensions/default-attributes/index.html new file mode 100644 index 0000000000..af0da8d31c --- /dev/null +++ b/2.5/extensions/default-attributes/index.html @@ -0,0 +1,525 @@ + + + + + + + + + + + + + + + + + Default Attributes Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Default Attributes

+ +

The DefaultAttributesExtension allows you to apply default HTML classes and other attributes using configuration options.

+ +

It works by applying the attributes to the nodes during the DocumentParsedEvent event - right after the nodes are parsed but before they are rendered. +(As a result, it’s possible that renderers may add other attributes - the goal of this extension is only to provide custom defaults.)

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DefaultAttributesExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
+use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Extension\DefaultAttributes\DefaultAttributesExtension;
+use League\CommonMark\Extension\Table\Table;
+use League\CommonMark\MarkdownConverter;
+use League\CommonMark\Node\Block\Paragraph;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'default_attributes' => [
+        Heading::class => [
+            'class' => static function (Heading $node) {
+                if ($node->getLevel() === 1) {
+                    return 'title-main';
+                } else {
+                    return null;
+                }
+            },
+        ],
+        Table::class => [
+            'class' => 'table',
+        ],
+        Paragraph::class => [
+            'class' => ['text-center', 'font-comic-sans'],
+        ],
+        Link::class => [
+            'class' => 'btn btn-link',
+            'target' => '_blank',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new DefaultAttributesExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a default_attributes array. Each key in the array should be a FQCN for the node class you wish to apply the default attribute to, and the values should be a map of attribute names to attribute values.

+ +

Attribute values may be any of the following types:

+ + + +

Examples

+ +

Here’s an example that will apply Bootstrap 4 classes and attributes:

+ +
$config = [
+    'default_attributes' => [
+        Table::class => [
+            'class' => ['table', 'table-responsive'],
+        ],
+        BlockQuote::class => [
+            'class' => 'blockquote',
+        ],
+    ],
+];
+
+ +

Here’s a more complex example that uses a callable to add a class only if the paragraph immediately follows an <h1> heading:

+ +
$config = [
+    'default_attributes' => [
+        Paragraph::class => [
+            'class' => static function (Paragraph $paragraph) {
+                if ($paragraph->previous() instanceof Heading && $paragraph->previous()->getLevel() === 1) {
+                    return 'lead';
+                }
+
+                return null;
+            },
+        ],
+    ],
+];
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/description-lists/index.html b/2.5/extensions/description-lists/index.html new file mode 100644 index 0000000000..8ac49f4c45 --- /dev/null +++ b/2.5/extensions/description-lists/index.html @@ -0,0 +1,475 @@ + + + + + + + + + + + + + + + + + Description List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Description List Extension

+ +

The DescriptionListExtension adds Markdown Extra-style description lists to facilitate the creation of <dl>, <dt>, and <dd> HTML using Markdown.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DescriptionListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\DescriptionList\DescriptionListExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DescriptionListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some markdown goes here');
+
+ +

Syntax

+ +

The syntax is based directly on the rules and logic implemented by the Markdown Extra library. Here are some examples of sample Markdown input and HTML output demonstrating the syntax:

+ +
Apple
+:   Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.
+:   An American computer company.
+
+Orange
+:   The fruit of an evergreen tree of the genus Citrus.
+
+ +
<dl>
+    <dt>Apple</dt>
+    <dd>Pomaceous fruit of plants of the genus Malus in
+    the family Rosaceae.</dd>
+    <dd>An American computer company.</dd>
+
+    <dt>Orange</dt>
+    <dd>The fruit of an evergreen tree of the genus Citrus.</dd>
+</dl>
+
+ +

See the Markdown Extra documentation or our own spec for additional examples.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/disallowed-raw-html/index.html b/2.5/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..5fcee57d04 --- /dev/null +++ b/2.5/extensions/disallowed-raw-html/index.html @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + Disallowed Raw HTML Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Disallowed Raw HTML Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The DisallowedRawHtmlExtension automatically escapes certain HTML tags when rendering raw HTML, such as:

+ + + +

Filtering is done by replacing the leading < with the entity &lt;.

+ +

This is required by the GFM spec because these particular tags could cause undesirable side-effects if a malicious user tries to introduce them.

+ +

All other HTML tags are left untouched by this extension.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the DisallowedRawHtmlExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Customize the extension's configuration if needed
+// Default values are shown below - you can omit this configuration if you're happy with those defaults
+// and don't want to customize them
+$config = [
+    'disallowed_raw_html' => [
+        'disallowed_tags' => ['title', 'textarea', 'style', 'xmp', 'iframe', 'noembed', 'noframes', 'script', 'plaintext'],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new DisallowedRawHtmlExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I cannot change the page <title>anymore</title>');
+
+ +

Configuration

+ +

This extension can be configured by providing a disallowed_raw_html array with the following nested configuration options. The defaults are shown in the code example above.

+ +

disallowed_tags

+ +

An array containing a list of tags that should be escaped.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/embed/index.html b/2.5/extensions/embed/index.html new file mode 100644 index 0000000000..0a6c08cd23 --- /dev/null +++ b/2.5/extensions/embed/index.html @@ -0,0 +1,563 @@ + + + + + + + + + + + + + + + + + Embed Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Embed Extension

+ +

This extension can embed rich content (like videos, tweets, etc.) from other websites.

+ +

The syntax is very simple - simply place any https:// URL on its own line like this:

+ +
Check out this video!
+
+https://www.youtube.com/watch?v=dQw4w9WgXcQ
+
+ +

If the link points to embeddable content, it will be replaced with the rich HTML needed to embed it:

+ +
<p>Check out this video:</p>
+<iframe width="200" height="113" src="https://www.youtube.com/embed/dQw4w9WgXcQ?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

You’ll also need to install a third-party OEmbed library - see the Adapter section below.

+ +

Usage

+ +

Configure your Environment as usual and add the EmbedExtension provided by this package:

+ +
use Embed\Embed;
+use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Embed\EmbedExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'embed' => [
+        'adapter' => new OscaroteroEmbedAdapter(), // See the "Adapter" documentation below
+        'allowed_domains' => ['youtube.com', 'twitter.com', 'github.com'],
+        'fallback' => 'link',
+    ],
+];
+
+// Configure the Environment with all whatever other extensions you want
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new EmbedExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
+
+ +

Configuration

+ +

This extension supports the following configuration options under the embed configuration:

+ +

adapter option

+ +

Any instance of EmbedAdapterInterface - see the “Adapter” section below.

+ +

allowed_domains option

+ +

This option defines a list of hosts that you wish to allow embedding content from. For example, setting this to +['youtube.com'] would only allow videos from YouTube to be embedded. +It’s extremely important that you only include websites you trust since they’ll be providing HTML that is directly embedded in your website.

+ +

Any subdomains of these domains will also be allowed. For example, ['youtube.com'] would allow embedding from youtube.com or www.youtube.com.

+ +

As an additional safety measure, we recommend that you also use a Content Security Policy (CSP) +to prevent unexpected content from being embedded.

+ +

By default, this option is an empty array ([]), which means that all domains are allowed.

+ +

fallback option

+ +

This options defines the behavior when a URL cannot be embedded, either because it’s not in the list of allowed_domains, +or because the adapter could not find embeddable content for that URL.

+ +

There are two possible values for this option:

+ + + +

Adapter

+ +

league/commonmark doesn’t know how to obtain the embeddable HTML for a given URL - this must be done by an external library.

+ +

embed/embed Adapter

+ +

We do provide an adapter for the popular embed/embed library. if you’d like to use that. We like this library +because it supports fetching multiple URLs in parallel, which is ideal for performance, and it supports a wide range +of embeddable content.

+ +

To use that library, you’ll need to composer install embed/embed and then pass new OscaroteroEmbedAdapter() as the adapter +configuration option, as shown in the Usage section above.

+ +

Note: embed/embed requires a PSR-17 implementation to be installed. If you do not have one installed, the library will not work. By default these libraries are detected automatically:

+ + + +

Need to customize the maximum width/height of the embedded content? You can do that by instantiating the service provided by +embed/embed, configuring it as needed, and passing that customized instance into the adapter:

+ +
use Embed\Embed;
+use League\CommonMark\Extension\Embed\Bridge\OscaroteroEmbedAdapter;
+
+// Configure the Embed library itself
+$embedLibrary = new Embed();
+$embedLibrary->setSettings([
+    'oembed:query_parameters' => [
+        'maxwidth' => 800,
+        'maxheight' => 600,
+    ],
+    'twitch:parent' => 'example.com',
+    'facebook:token' => '1234|5678',
+    'instagram:token' => '1234|5678',
+    'twitter:token' => 'asdf',
+]);
+
+// Inject it into our adapter
+$config = [
+    'adapter' => new OscaroteroEmbedAdapter($embedLibrary),
+];
+
+// Instantiate your CommonMark environment and converter like usual
+// ...
+
+ +

Custom Adapter

+ +

If you prefer to use a different library, you’ll need to implement our EmbedAdapterInterface yourself with +whatever OEmbed library you choose.

+ +

Tips

+ +

If you need to wrap the HTML in a container tag, consider using the HtmlDecorator renderer:

+ +
$environment->addRenderer(Embed::class, new HtmlDecorator(new EmbedRenderer(), 'div', ['class' => 'embeded-content']));
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/external-links/index.html b/2.5/extensions/external-links/index.html new file mode 100644 index 0000000000..e49b7a3d0a --- /dev/null +++ b/2.5/extensions/external-links/index.html @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + External Links Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

External Links Extension

+ +

This extension can detect links to external sites and adjust the markup accordingly:

+ + + +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the ExternalLinkExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\ExternalLink\ExternalLinkExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'external_link' => [
+        'internal_hosts' => 'www.example.com', // TODO: Don't forget to set this!
+        'open_in_new_window' => true,
+        'html_class' => 'external-link',
+        'nofollow' => '',
+        'noopener' => 'external',
+        'noreferrer' => 'external',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new ExternalLinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('I successfully installed the <https://github.com/thephpleague/commonmark> project!');
+
+ +

Configuration

+ +

This extension supports three configuration options under the external_link configuration:

+ +

internal_hosts

+ +

This option defines a list of hosts which are considered non-external and should not receive the external link treatment.

+ +

This can be a single host name, like 'example.com', which must match exactly.

+ +

Wildcard matching is also supported using regular expression like '/(^|\.)example\.com$/'. Note that you must use / characters to delimit your regex.

+ +

This configuration option also accepts an array of multiple strings and/or regexes:

+ +
$config = [
+    'external_link' => [
+        'internal_hosts' => ['foo.example.com', 'bar.example.com', '/(^|\.)google\.com$/],
+    ],
+];
+
+ +

By default, if this option is not provided, all links will be considered external.

+ +

open_in_new_window

+ +

This option (which defaults to false) determines whether any external links should open in a new tab/window.

+ +

html_class

+ +

This option allows you to provide a string containing one or more HTML classes that should be added to the external link <a> tags: No classes are added by default.

+ +

nofollow, noopener, and noreferrer

+ +

These options allow you to configure whether a rel attribute should be applied to links. Each of these options can be set to one of the following string values:

+ + + +

Unless you override these options, nofollow defaults to '' and the others default to 'external'.

+ +

Advanced Rendering

+ +

When an external link is detected, the ExternalLinkProcessor will set the external data option on the Link node to either true or false. You can therefore create a custom link renderer which checks this value and behaves accordingly:

+ +
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
+use League\CommonMark\Renderer\ChildNodeRendererInterface;
+use League\CommonMark\Renderer\NodeRendererInterface;
+use League\CommonMark\Util\HtmlElement;
+
+class MyCustomLinkRenderer implements NodeRendererInterface
+{
+    /**
+     * @param Node                       $node
+     * @param ChildNodeRendererInterface $childRenderer
+     *
+     * @return HtmlElement
+     */
+    public function render(Node $node, ChildNodeRendererInterface $childRenderer)
+    {
+        Link::assertInstanceOf($node);
+
+        if ($node->data->get('external')) {
+            // This is an external link - render it accordingly
+        } else {
+            // This is an internal link
+        }
+
+        // ...
+    }
+}
+
+ +

Adding Icons

+ +

You can also use CSS to automagically add an external link icon by targeting the html_class given in the configuration:

+ +
// Font Awesome example:
+a[target="_blank"]::after,
+a.external::after {
+   content: "\f08e";
+   font: normal normal normal 14px/1 FontAwesome;
+}
+
+// Glyphicon example:
+a[target="_blank"]::after,
+a.external::after {
+  @extend .glyphicon;
+  content: "\e164";
+  margin-left: .5em;
+  margin-right: .25em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/footnotes/index.html b/2.5/extensions/footnotes/index.html new file mode 100644 index 0000000000..9d7f7125f9 --- /dev/null +++ b/2.5/extensions/footnotes/index.html @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + Footnote Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Footnotes

+ +

The FootnoteExtension adds the ability to create footnotes in Markdown documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Footnote Syntax

+ +

Sample Markdown input:

+ +
Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi[^note1] leo risus, porta ac consectetur ac.
+
+[^note1]: Elit Malesuada Ridiculus
+
+ +

Result:

+ +
<p>
+    Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit.
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+    Morbi<sup id="fnref:note1"><a class="footnote-ref" href="#fn:note1" role="doc-noteref">1</a></sup> leo risus, porta ac consectetur ac.
+</p>
+<div class="footnotes">
+    <hr />
+    <ol>
+        <li class="footnote" id="fn:note1">
+            <p>
+                Elit Malesuada Ridiculus <a class="footnote-backref" rev="footnote" href="#fnref:note1"></a>
+            </p>
+        </li>
+    </ol>
+</div>
+
+ +

Usage

+ +

Configure your Environment as usual and simply add the FootnoteExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Footnote\FootnoteExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'footnote' => [
+        'backref_class'      => 'footnote-backref',
+        'backref_symbol'     => '↩',
+        'container_add_hr'   => true,
+        'container_class'    => 'footnotes',
+        'ref_class'          => 'footnote-ref',
+        'ref_id_prefix'      => 'fnref:',
+        'footnote_class'     => 'footnote',
+        'footnote_id_prefix' => 'fn:',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FootnoteExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert("This is a footnote[^test] test.\n\n[^test]: Doesn't it look good!");
+
+ +

Configuration

+ +

This extension can be configured by providing a footnote array with several nested configuration options. The defaults are shown in the code example above.

+ +

backref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote backreference elements.

+ +

backref_symbol

+ +

This string option sets the symbol used as the contents of the footnote backreference link. It defaults to \League\CommonMark\Extension\Footnote\Renderer\FootnoteBackrefRenderer::DEFAULT_SYMBOL = '↩'.

+ +

If you want to use a custom icon, set this to an empty string '' and take a look at the Adding Icons section below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

container_add_hr

+ +

This boolean option controls whether an <hr> element should be added inside the container. Set this to false if you want more control over how the footnote section at the bottom is differentiated from the rest of the document.

+ +

container_class

+ +

This string option defines which HTML class should be assigned to the container at the bottom of the page which shows all the footnotes.

+ +

ref_class

+ +

This string option defines which HTML class should be assigned to rendered footnote reference elements.

+ +

ref_id_prefix

+ +

This string option defines the prefix prepended to footnote references.

+ +

footnote_class

+ +

This string option defines which HTML class should be assigned to rendered footnote elements.

+ +

footnote_id_prefix

+ +

This string option defines the prefix prepended to footnote elements.

+ +

Adding Icons

+ +

You can use CSS to add a custom icon instead of providing a backref_symbol:

+ +
$config = [
+    'footnote' => [
+        'backref_class' => 'footnote-backref',
+        'backref_symbol' => '',
+    ],
+];
+
+ +

Then target the backref_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.footnote-backref::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/front-matter/index.html b/2.5/extensions/front-matter/index.html new file mode 100644 index 0000000000..8d6664f596 --- /dev/null +++ b/2.5/extensions/front-matter/index.html @@ -0,0 +1,548 @@ + + + + + + + + + + + + + + + + + Front Matter Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Front Matter Extension

+ +

The FrontMatterExtension adds the ability to parse YAML front matter from the Markdown document and include that in the return result.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

You will also need to install symfony/yaml or the YAML extension for PHP to use this extension. For symfony/yaml:

+ +
composer require symfony/yaml
+
+ +

(You can use any version of symfony/yaml 2.5 or higher, though we recommend using 4.0 or higher.)

+ +

Front Matter Syntax

+ +

This extension follows the Jekyll Front Matter syntax. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. Here is a basic example:

+ +
---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+
+ +

This will produce a front matter array similar to this:

+ +
$parsedFrontMatter = [
+    'layout' => 'post',
+    'title' => 'I Love Markdown',
+    'tags' => [
+        'test',
+        'example',
+    ],
+];
+
+ +

And the HTML output will only contain the one heading:

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

Usage

+ +

Configure your Environment as usual and add the FrontMatterExtension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+use League\CommonMark\Extension\FrontMatter\Output\RenderedContentWithFrontMatter;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the extension
+$environment->addExtension(new FrontMatterExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+// A sample Markdown file with some front matter:
+$markdown = <<<MD
+---
+layout: post
+title: I Love Markdown
+tags:
+  - test
+  - example
+---
+
+# Hello World!
+MD;
+
+$result = $converter->convert($markdown);
+
+// Grab the front matter:
+if ($result instanceof RenderedContentWithFrontMatter) {
+    $frontMatter = $result->getFrontMatter();
+}
+
+// Output the HTML using any of these:
+echo $result;               // implicit string cast
+// or:
+echo (string) $result;      // explicit string cast
+// or:
+echo $result->getContent();
+
+ +

Parsing Front Matter Only

+ +

You don’t have to parse the entire file (including all the Markdown) if you only want the front matter. You can either instantiate the front matter parser yourself and call it directly, like this:

+ +
use League\CommonMark\Extension\FrontMatter\Data\LibYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\Data\SymfonyYamlFrontMatterParser;
+use League\CommonMark\Extension\FrontMatter\FrontMatterParser;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+// For `symfony/yaml`
+$frontMatterParser = new FrontMatterParser(new SymfonyYamlFrontMatterParser());
+// For YAML extension
+$frontMatterParser = new FrontMatterParser(new LibYamlFrontMatterParser());
+$result = $frontMatterParser->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

Or you can use the getFrontMatterParser() method from the extension:

+ +
use League\CommonMark\Extension\FrontMatter\FrontMatterExtension;
+
+$markdown = '...'; // TODO: Load some Markdown content somehow
+
+$frontMatterExtension = new FrontMatterExtension();
+$result = $frontMatterExtension->getFrontMatterParser()->parse($markdown);
+
+var_dump($result->getFrontMatter()); // The parsed front matter
+var_dump($result->getContent()); // Markdown content without the front matter
+
+ +

This latter approach may be more convenient if you have already instantiated a FrontMatterExtension object you’re adding to the Environment somewhere and just want to call that.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/github-flavored-markdown/index.html b/2.5/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..e45769c506 --- /dev/null +++ b/2.5/extensions/github-flavored-markdown/index.html @@ -0,0 +1,473 @@ + + + + + + + + + + + + + + + + + GitHub-Flavored Markdown - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

GitHub-Flavored Markdown

+ +

You can manually add the GFM extension to your environment like this:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark and GFM parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This will automatically include all of these sub-extensions/features for you:

+ + + +

Or, if you only want a subset of GFM extensions, you can add them individually like this instead:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Remove any of the lines below if you don't want a particular feature
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+$environment->addExtension(new TaskListExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello GFM!');
+
+ +

This extension relies on the CommonMarkCoreExtension being enabled, so don’t forget to include that too.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/heading-permalinks/index.html b/2.5/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..6e4f0e4d60 --- /dev/null +++ b/2.5/extensions/heading-permalinks/index.html @@ -0,0 +1,631 @@ + + + + + + + + + + + + + + + + + Heading Permalink Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Heading Permalink Extension

+ +

This extension makes all of your heading elements (<h1>, <h2>, etc) linkable so that users can quickly grab a link to that specific part of the document - almost like the headings in this documentation!

+ +

Tip: You can combine this with the Table of Contents extension to automatically generate a list of links to the headings in your documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkExtension;
+use League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer;
+use League\CommonMark\MarkdownConverter;
+
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'id_prefix' => 'content',
+        'apply_id_to_heading' => false,
+        'heading_class' => '',
+        'fragment_prefix' => 'content',
+        'insert' => 'before',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'title' => 'Permalink',
+        'symbol' => HeadingPermalinkRenderer::DEFAULT_SYMBOL,
+        'aria_hidden' => true,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new HeadingPermalinkExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ +

Configuration

+ +

This extension can be configured by providing a heading_permalink array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <a> tag’s class attribute. This defaults to 'heading-permalink'.

+ +

id_prefix

+ +

This should be a string you want prepended to HTML IDs. This prevents generating HTML ID attributes which might conflict with others in your stylesheet. A dash separator (-) will be added between the prefix and the ID. You can instead set this to an empty string ('') if you don’t want a prefix.

+ +

apply_id_to_heading

+ +

If this value is true, the id attributes will be written to the <h> tag instead of the <a>.

+ +

heading_class

+ +

The class will be added to the <h> tag (no matter if apply_id_to_heading is set true or false)

+ +

fragment_prefix

+ +

This should be a string you want prepended to the URL fragment in the link’s href attribute. This should typically be set to the same value as id_prefix for links to work properly. However, you may not want to expose that same prefix in your URLs - in that case, you can set this to something different (even an empty string) and use JavaScript to “rewrite” them.

+ +

For example, to emulate how GitHub heading permalinks work, set id_prefix to 'user-content', set fragment_prefix to '', and insert some JavaScript into the page like this:

+ +
var scrollToPermalink = function() {
+    var link = document.getElementById('user-content-' + window.location.hash);
+    if (link) {
+        link.scrollIntoView({behavior: 'smooth'});
+    }
+};
+
+window.addEventListener('hashchange', scrollToPermalink);
+if (window.location.hash) {
+    scrollToPermalink();
+}
+
+ +

insert

+ +

This controls whether the anchor is added to the beginning of the heading tag (before), the end of the tag (after), or not added at all (none).

+ +

min_heading_level and max_heading_level

+ +

These two settings control which headings should have permalinks added. By default, all 6 levels (1, 2, 3, 4, 5, and 6) will have them. You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

symbol

+ +

This option sets the symbol used to display the permalink on the document. This defaults to \League\CommonMark\Extension\HeadingPermalink\HeadingPermalinkRenderer::DEFAULT_SYMBOL = '¶'.

+ +

If you want to use a custom icon, then set this to an empty string '' and check out the Adding Icons sections below.

+ +
+

Note: Special HTML characters (" & < >) provided here will be escaped for security reasons.

+
+ +

title

+ +

This option sets the title attribute on the <a> tag. This defaults to 'Permalink'.

+ +

aria_hidden

+ +

This option sets the aria-hidden attribute on the <a> tag. This defaults to aria-hidden="true".

+ +

Setting this option to false would render the <a> tag excluding the aria-hidden entirely.

+ +

Example

+ +

If you wanted to style your headings exactly like this documentation page does, try this configuration!

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'insert' => 'after',
+        'symbol' => '¶',
+        'title' => "Permalink",
+    ],
+];
+
+ +

Along with this CSS:

+ +
.heading-permalink {
+    font-size: .8em;
+    vertical-align: super;
+    text-decoration: none;
+    color: transparent;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink,
+.heading-permalink:hover {
+    text-decoration: none;
+    color: #777;
+}
+
+ +

Styling Ideas

+ +

This library doesn’t provide any CSS styling for the anchor element(s), but here are some ideas you could use in your own stylesheet.

+ +

You could hide the icon until the user hovers over the heading:

+ +
.heading-permalink {
+  visibility: hidden;
+}
+
+h1:hover .heading-permalink,
+h2:hover .heading-permalink,
+h3:hover .heading-permalink,
+h4:hover .heading-permalink,
+h5:hover .heading-permalink,
+h6:hover .heading-permalink
+{
+  visibility: visible;
+}
+
+ +

You could also float the symbol just a little bit left of the heading:

+ +
.heading-permalink {
+  float: left;
+  padding-right: 4px;
+  margin-left: -20px;
+  line-height: 1;
+}
+
+ +

These are only ideas - feel free to customize this however you’d like!

+ +

Adding Icons

+ +

You can also use CSS to add a custom icon instead of providing a symbol:

+ +
$config = [
+    'heading_permalink' => [
+        'html_class' => 'heading-permalink',
+        'symbol' => '',
+    ],
+];
+
+ +

Then targeting the html_class given in the configuration in your CSS:

+ +
/**
+ * Custom SVG Icon.
+ */
+.heading-permalink::after {
+  display: inline-block;
+  content: "";
+  /**
+   * Octicon Link (https://iconify.design/icon-sets/octicon/link.html)
+   * [Pro Tip] Use an SVG URL encoder (https://yoksel.github.io/url-encoder).
+   */
+  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' aria-hidden='true' style='-ms-transform:rotate(360deg);-webkit-transform:rotate(360deg)' viewBox='0 0 16 16' transform='rotate(360)'%3E%3Cpath fill-rule='evenodd' d='M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z' fill='%23626262'/%3E%3C/svg%3E");
+  background-repeat: no-repeat;
+  background-size: 1em;
+}
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/inlines-only/index.html b/2.5/extensions/inlines-only/index.html new file mode 100644 index 0000000000..7f3b78786d --- /dev/null +++ b/2.5/extensions/inlines-only/index.html @@ -0,0 +1,446 @@ + + + + + + + + + + + + + + + + + Inlines Only Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Inlines Only Extension

+ +

This extension configures the parser to only render inline elements - no paragraph tags, headers, code blocks, etc. This makes it perfect for commenting systems where you only want users having bold, italics, links, etc.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Although you normally add extra extensions along with the default CommonMark Core extension, we’re not going to do that here, because this is essentially a slimmed-down version of the core extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\InlinesOnly\InlinesOnlyExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Create a new, empty environment
+$environment = new Environment($config);
+
+// Add this extension
+$environment->addExtension(new InlinesOnlyExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('**Hello World!**');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/mentions/index.html b/2.5/extensions/mentions/index.html new file mode 100644 index 0000000000..a852de7fbc --- /dev/null +++ b/2.5/extensions/mentions/index.html @@ -0,0 +1,672 @@ + + + + + + + + + + + + + + + + + Mention Parser - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Mention Extension

+ +

The MentionExtension makes it easy to parse shortened mentions and references like @colinodell to a Twitter URL +or #123 to a GitHub issue URL. You can create your own custom syntax by defining which prefix you want to use and +how to generate the corresponding URL.

+ +

Usage

+ +

You can create your own custom syntax by supplying the configuration with an array of options that +define the starting prefix, a regular expression to match against, and any custom URL template or callable to +generate the URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        // GitHub handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.github.com/colinodell">@colinodell</a>`
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            'generator' => 'https://github.com/%s',
+        ],
+        // GitHub issue mention configuration.
+        // Sample Input:  `#473`
+        // Sample Output: `<a href="https://github.com/thephpleague/commonmark/issues/473">#473</a>`
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            'generator' => "https://github.com/thephpleague/commonmark/issues/%d",
+        ],
+        // Twitter handler mention configuration.
+        // Sample Input:  `@colinodell`
+        // Sample Output: `<a href="https://www.twitter.com/colinodell">@colinodell</a>`
+        // Note: when registering more than one mention parser with the same prefix, the first mention parser to
+        // successfully match and return a properly constructed Mention object (where the URL has been set) will be the
+        // the mention parser that is used. In this example, the GitHub handle would actually match first because
+        // there isn't any real validation to check whether https://www.github.com/colinodell exists. However, in
+        // CMS applications, you could check whether its a local user first, then check Twitter and then GitHub, etc.
+        'twitter_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[A-Za-z0-9_]{1,15}(?!\w)',
+            'generator' => 'https://twitter.com/%s',
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on GitHub: @colinodell');
+// Output:
+// <p>Follow me on GitHub: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

String-Based URL Templates

+ +

URL templates are perfect for situations where the identifier is inserted directly into a URL:

+ +
"@colinodell" => https://www.twitter.com/colinodell
+ ▲└────┬───┘                             └───┬────┘
+ │     │                                     │
+Prefix └───────────── Identifier ────────────┘
+
+ +

Examples of using string-based URL templates can be seen in the usage example above - you simply provide a string to the generator option.

+ +

Note that the URL template must be a string, and that the %s placeholder will be replaced by whatever the user enters after the prefix (in this case, @). You can use any prefix, regular expression pattern (without opening/closing delimiter or modifiers), or URL template you want!

+ +

Custom Callback-Based Parsers

+ +

Need more power than simply adding the mention inside a string based URL template? The MentionExtension automatically +detects if the provided generator is an object that implements \League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface +or a valid PHP callable that can generate a +resulting URL.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\Node\Inline\AbstractInline;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'github_handle' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}(?!\w)',
+            // The recommended approach is to provide a class that implements MentionGeneratorInterface.
+            'generator' => new GithubUserMentionGenerator(), // TODO: Implement such a class yourself
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Alternatively, if your logic is simple, you can implement an inline anonymous class like this example.
+            'generator' => new class implements MentionGeneratorInterface {
+                 public function generateMention(Mention $mention): ?AbstractInline
+                 {
+                     $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                     return $mention;
+                 }
+             },
+        ],
+        'github_issue' => [
+            'prefix'    => '#',
+            'pattern'   => '\d+',
+            // Any type of callable, including anonymous closures, (with optional typehints) are also supported.
+            // This allows for better compatibility between different major versions of CommonMark.
+            // However, you sacrifice the ability to type-check which means automated development tools
+            // may not notice if your code is no longer compatible with new versions - you'll need to
+            // manually verify this yourself.
+            'generator' => function ($mention) {
+                // Immediately return if not passed the supported Mention object.
+                // This is an example of the types of manual checks you'll need to perform if not using type hints
+                if (!($mention instanceof Mention)) {
+                    return null;
+                }
+
+                $mention->setUrl(\sprintf('https://github.com/thephpleague/commonmark/issues/%d', $mention->getIdentifier()));
+
+                return $mention;
+            },
+        ],
+
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Follow me on Twitter: @colinodell');
+// Output:
+// <p>Follow me on Twitter: <a href="https://www.github.com/colinodell">@colinodell</a></p>
+
+ +

When implementing MentionGeneratorInterface or a simple callable, you’ll receive a single Mention parameter and must either:

+ + + +

Here’s a faux-real-world example of how you might use such a generator for your application. Imagine you +want to parse @username into custom user profile links for your application, but only if the user exists. You could +create a class like the following which integrates with the framework your application is built on:

+ +
use League\CommonMark\Extension\Mention\Generator\MentionGeneratorInterface;
+use League\CommonMark\Extension\Mention\Mention;
+use League\CommonMark\Inline\Element\AbstractInline;
+
+class UserMentionGenerator implements MentionGeneratorInterface
+{
+    private $currentUser;
+    private $userRepository;
+    private $router;
+
+    public function __construct (AccountInterface $currentUser, UserRepository $userRepository, Router $router)
+    {
+        $this->currentUser = $currentUser;
+        $this->userRepository = $userRepository;
+        $this->router = $router;
+    }
+
+    public function generateMention(Mention $mention): ?AbstractInline
+    {
+        // Determine mention visibility (i.e. member privacy).
+        if (!$this->currentUser->hasPermission('access profiles')) {
+            $emphasis = new \League\CommonMark\Inline\Element\Emphasis();
+            $emphasis->appendChild(new \League\CommonMark\Inline\Element\Text('[members only]'));
+            return $emphasis;
+        }
+
+        // Locate the user that is mentioned.
+        $user = $this->userRepository->findUser($mention->getIdentifier());
+
+        // The mention isn't valid if the user does not exist.
+        if (!$user) {
+            return null;
+        }
+
+        // Change the label.
+        $mention->setLabel($user->getFullName());
+        // Use the path to their profile as the URL, typecasting to a string in case the service returns
+        // a __toString object; otherwise you will need to figure out a way to extract the string URL
+        // from the service.
+        $mention->setUrl((string) $this->router->generate('user_profile', ['id' => $user->getId()]));
+
+        return $mention;
+    }
+}
+
+ +

You can then hook this class up to a mention definition in the configuration to generate profile URLs from Markdown +mentions:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Mention\MentionExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Grab your UserMentionGenerator somehow, perhaps from a DI container or instantiate it if needed
+$userMentionGenerator = $container->get(UserMentionGenerator::class);
+
+// Define your configuration
+$config = [
+    'mentions' => [
+        'user_url_generator' => [
+            'prefix'    => '@',
+            'pattern'   => '[a-z0-9]+',
+            'generator' => $userMentionGenerator,
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the Mention extension.
+$environment->addExtension(new MentionExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('You should ask @colinodell about that');
+
+// Output (if current user has permission to view profiles):
+// <p>You should ask <a href="/user/123/profile">Colin O'Dell</a> about that</p>
+//
+// Output (if current user doesn't have has access to view profiles):
+// <p>You should ask <em>[members only]</em> about that</p>
+
+ +

Rendering

+ +

Whenever a mention is found, a Mention object is added to the document’s AST. +This object extends from Link, so it’ll be rendered as a normal <a> tag by default.

+ +

If you need more control over the output you can implement a custom renderer for the Mention type +and convert it to whatever HTML you wish!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/overview/index.html b/2.5/extensions/overview/index.html new file mode 100644 index 0000000000..7c7648f6b3 --- /dev/null +++ b/2.5/extensions/overview/index.html @@ -0,0 +1,604 @@ + + + + + + + + + + + + + + + + + Extensions Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Extensions Overview

+ +

Extensions provide a simple way to add new syntax and features to the CommonMark parser.

+ +

Included Extensions

+ +

Starting with version 1.3.0, this library includes several extensions to support GitHub Flavored Markdown (GFM) and +many other common use-cases. Most of these extensions started out as 3rd-party community based extensions that have +since been officially adopted by this library in an effort to ensure future compatibility and to provide an easy way +to enhance your experience out-of-the-box depending on your specific use-cases.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ExtensionPurposeVersion IntroducedGFM
AttributesAdd HTML attributes (like id and class) from within the Markdown content1.5.0 
AutolinksEnables automatic linking of URLs within text without needing to wrap them with Markdown syntax1.3.0
Default AttributesEasily apply default HTML classes using configuration options to match your site’s styles2.0.0 
Description ListsCreate <dl> description lists using Markdown Extra’s syntax2.0.0 
Disallowed Raw HTMLDisables certain kinds of HTML tags that could affect page rendering1.3.0
EmbedEmbed rich content (like videos, tweets, and more) from other websites2.3.0 
External LinksTags external links with additional markup1.3.0 
FootnotesAdd footnote references throughout the document and show a listing of them at the bottom1.5.0 
Front MatterParses YAML front matter from your Markdown input2.0.0 
GitHub Flavored MarkdownEnables full support for GFM. Automatically includes the extensions noted in the GFM column (though you can certainly add them individually if you wish):1.3.0 
Heading PermalinksMakes heading elements linkable1.4.0 
Inlines OnlyOnly includes standard CommonMark inline elements - perfect for handling comments and other short bits of text where you only want bold, italic, links, etc.1.3.0 
MentionsEasy parsing of @mention and #123-style references1.5.0 
StrikethroughAllows using tilde characters (~~) for ~strikethrough~ formatting1.3.0
TablesEnables you to create HTML tables1.3.0
Table of ContentsAutomatically inserts links to the headings at the top of your document1.4.0 
Task ListsAllows the creation of task lists1.3.0
Smart PunctuationIntelligently converts ASCII quotes, dashes, and ellipses to their fancy Unicode equivalents1.3.0 
+ +

Usage

+ +

You can enable extensions by simply calling ->addExtension() on the Environment.

+ +

In an effort to streamline the extensions used in GitHub Flavored Markdown (GFM), a special extension named +GithubFlavoredMarkdownExtension can be used that will automatically add all the extensions checked in the GFM +column above for you:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\GithubFlavoredMarkdownExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the extensions you need
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+$environment->addExtension(new GithubFlavoredMarkdownExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

Or maybe you only want a subset of GFM extensions, plus the Smart Punctuation extension:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\Autolink\AutolinkExtension;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\DisallowedRawHtml\DisallowedRawHtmlExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the other extensions you need
+$environment->addExtension(new AutolinkExtension());
+$environment->addExtension(new DisallowedRawHtmlExtension());
+$environment->addExtension(new SmartPunctExtension());
+$environment->addExtension(new StrikethroughExtension());
+$environment->addExtension(new TableExtension());
+
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Hello World!');
+
+ +

The extension system makes it easy to mix-and-match extensions to fit your needs.

+ +

Writing Custom Extensions

+ +

See the Custom Extensions page for details on how you can create your own custom extensions.

+ + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/smart-punctuation/index.html b/2.5/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..4d45dfcc7b --- /dev/null +++ b/2.5/extensions/smart-punctuation/index.html @@ -0,0 +1,465 @@ + + + + + + + + + + + + + + + + + Smart Punctuation Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Smart Punctuation Extension

+ +

The SmartPunctExtension Intelligently converts ASCII quotes, dashes, and ellipses to their Unicode equivalents.

+ +

For example, this Markdown…

+ +
"CommonMark is the PHP League's Markdown parser," she said.  "It's super-configurable... you can even use additional extensions to expand its capabilities -- just like this one!"
+
+ +

Will result in this HTML:

+ +
<p>“CommonMark is the PHP League’s Markdown parser,” she said.  “It’s super-configurable… you can even use additional extensions to expand its capabilities – just like this one!”</p>
+
+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Extensions can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\SmartPunct\SmartPunctExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'smartpunct' => [
+        'double_quote_opener' => '“',
+        'double_quote_closer' => '”',
+        'single_quote_opener' => '‘',
+        'single_quote_closer' => '’',
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new SmartPunctExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Hello World!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/strikethrough/index.html b/2.5/extensions/strikethrough/index.html new file mode 100644 index 0000000000..5af93e025b --- /dev/null +++ b/2.5/extensions/strikethrough/index.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + + Strikethrough Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Strikethrough Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style strikethrough syntax. It allows users to use ~~ in order to indicate text that should be rendered within <del> tags.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

This extension can be added to any new Environment:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Strikethrough\StrikethroughExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new StrikethroughExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('This extension is ~~really good~~ great!');
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/table-of-contents/index.html b/2.5/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..887672866a --- /dev/null +++ b/2.5/extensions/table-of-contents/index.html @@ -0,0 +1,603 @@ + + + + + + + + + + + + + + + + + Table of Contents Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Table of Contents Extension

+ +

The TableOfContentsExtension automatically inserts a table of contents into your document with links to the various headings.

+ +

The Heading Permalink extension must also be included for this to work.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableOfContentsExtension and HeadingPermalinkExtension provided by this package:

+ +
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;
+
+// Define your configuration, if needed
+// Extension defaults are shown below
+// If you're happy with the defaults, feel free to remove them from this array
+$config = [
+    'table_of_contents' => [
+        'html_class' => 'table-of-contents',
+        'position' => 'top',
+        'style' => 'bullet',
+        'min_heading_level' => 1,
+        'max_heading_level' => 6,
+        'normalize' => 'relative',
+        'placeholder' => null,
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add the two extensions
+$environment->addExtension(new HeadingPermalinkExtension());
+$environment->addExtension(new TableOfContentsExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('# Awesome!');
+
+ +

Configuration

+ +

This extension can be configured by providing a table_of_contents array with several nested configuration options. The defaults are shown in the code example above.

+ +

html_class

+ +

The value of this nested configuration option should be a string that you want set as the <ul> or <ol> tag’s class attribute. This defaults to 'table-of-contents'.

+ +

normalize

+ +

This should be a string that defines one of three different strategies to use when generating a (potentially-nested) list from your various headings:

+ + + +

See “Normalization Strategies” below for more information.

+ +

position

+ +

This string controls where in the document your table of contents will be placed. There are two options:

+ + + +

If you’d like to customize this further, you can implement a custom event listener to locate the TableOfContents node and reposition it somewhere else in the document prior to rendering.

+ +

placeholder

+ +

When combined with 'position' => 'placeholder', this setting tells the extension which placeholder content should be replaced with the Table of Contents. For example, if you set this option to [TOC], then any lines in your document consisting of that [TOC] placeholder will be replaced by the Table of Contents. Note that this option has no default value - you must provide this string yourself.

+ +

style

+ +

This string option controls what style of HTML list should be used to render the table of contents:

+ + + +

min_heading_level and max_heading_level

+ +

These two settings control which headings should appear in the list. By default, all 6 levels (1, 2, 3, 4, 5, and 6). You can override this by setting the min_heading_level and/or max_heading_level to a different number (int value).

+ +

Normalization Strategies

+ +

Consider this sample Markdown input:

+ +
## Level 2 Heading
+
+This is a sample document that starts with a level 2 heading
+
+#### Level 4 Heading
+
+Notice how we went from a level 2 heading to a level 4 heading!
+
+### Level 3 Heading
+
+And now we have a level 3 heading here.
+
+ +

Here’s how the different normalization strategies would handle this input:

+ +

Strategy: 'flat'

+ +

All links in your table of contents will be shown in a flat, single-level list:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-4-heading">Level 4 Heading</a></p>
+    </li>
+    <li>
+        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'as-is'

+ +

Level 1 headings (<h1>) will appear on the first level of the list, with level 2 headings (<h2>) nested under those, and so forth - exactly as they occur within the document. But this can get weird if your document doesn’t start with level 1 headings, or it doesn’t properly nest the levels:

+ +
<ul class="table-of-contents">
+    <li>
+        <ul>
+            <li>
+                <p><a href="#level-2-heading">Level 2 Heading</a></p>
+                <ul>
+                    <li>
+                        <ul>
+                            <li>
+                                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+                            </li>
+                        </ul>
+                    </li>
+                    <li>
+                        <p><a href="#level-3-heading">Level 3 Heading</a></p>
+                    </li>
+                </ul>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ +

Strategy: 'relative'

+ +

Applies nesting, but handles edge cases (like incorrect nesting levels) as you’d expect:

+ +
<ul class="table-of-contents">
+    <li>
+        <p><a href="#level-2-heading">Level 2 Heading</a></p>
+        <ul>
+            <li>
+                <p><a href="#level-4-heading">Level 4 Heading</a></p>
+            </li>
+        </ul>
+        <ul>
+            <li>
+                <p><a href="#level-3-heading">Level 3 Heading</a></p>
+            </li>
+        </ul>
+    </li>
+</ul>
+
+<!-- The rest of the content would go here -->
+
+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/tables/index.html b/2.5/extensions/tables/index.html new file mode 100644 index 0000000000..67115bbb51 --- /dev/null +++ b/2.5/extensions/tables/index.html @@ -0,0 +1,563 @@ + + + + + + + + + + + + + + + + + Table Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Table Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

The TableExtension adds the ability to create tables in CommonMark documents.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TableExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\Table\TableExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => false,
+            'tag' => 'div',
+            'attributes' => [],
+        ],
+        'alignment_attributes' => [
+            'left'   => ['align' => 'left'],
+            'center' => ['align' => 'center'],
+            'right'  => ['align' => 'right'],
+        ],
+    ],
+];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TableExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+echo $converter->convert('Some Markdown with a table in it');
+
+ +

Syntax

+ +

This package is fully compatible with GFM-style tables:

+ +

Simple

+ +

Code:

+ +
th | th(center) | th(right)
+---|:----------:|----------:
+td | td         | td
+
+ +

Result:

+ +
<table>
+<thead>
+<tr>
+<th align="left">th</th>
+<th align="center">th(center)</th>
+<th align="right">th(right)/th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td align="left">td</td>
+<td align="center">td</td>
+<td align="right">td</td>
+</tr>
+</tbody>
+</table>
+
+ +

Advanced

+ +
| header 1 | header 2 | header 2 |
+| :------- | :------: | -------: |
+| cell 1.1 | cell 1.2 | cell 1.3 |
+| cell 2.1 | cell 2.2 | cell 2.3 |
+
+ +

Configuration

+ +

Wrapping Container

+ +

You can “wrap” the table with a container element by configuring the following options:

+ + + +

For example, to wrap all tables within a <div class="table-responsive"> container element:

+ +
$config = [
+    'table' => [
+        'wrap' => [
+            'enabled' => true,
+            'tag' => 'div',
+            'attributes' => ['class' => 'table-responsive'],
+        ],
+    ],
+];
+
+ +

Alignment

+ +

You can configure the HTML attributes used for alignment via the alignment_attributes option. For example, if you wanted Bootstrap classes to be applied, you could do so like this:

+ +
$config = [
+    'table' => [
+        'alignment_attributes' => [
+            'left' => ['class' => 'text-start'],
+            'center' => ['class' => 'text-center'],
+            'right' => ['class' => 'text-end'],
+        ],
+    ],
+];
+
+ +

Or you could use inline styles:

+ +
$config = [
+    'table' => [
+        'alignment_attributes' => [
+            'left' => ['style' => 'text-align:left'],
+            'center' => ['style' => 'text-align:center'],
+            'right' => ['style' => 'text-align:right'],
+        ],
+    ],
+];
+
+ +

Or any other HTML attributes you’d like!

+ +

Credits

+ +

The Table functionality was originally built by Martin Hasoň and Webuni s.r.o. before it was merged into the core parser.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/extensions/task-lists/index.html b/2.5/extensions/task-lists/index.html new file mode 100644 index 0000000000..9b0bcd1016 --- /dev/null +++ b/2.5/extensions/task-lists/index.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + + + + + Task List Extension - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Task List Extension

+ +

(Note: this extension is included by default within the GFM extension)

+ +

This extension adds support for GFM-style task lists.

+ +

Installation

+ +

This extension is bundled with league/commonmark. This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Usage

+ +

Configure your Environment as usual and simply add the TaskListExtension provided by this package:

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Extension\TaskList\TaskListExtension;
+use League\CommonMark\MarkdownConverter;
+
+// Define your configuration, if needed
+$config = [];
+
+// Configure the Environment with all the CommonMark parsers/renderers
+$environment = new Environment($config);
+$environment->addExtension(new CommonMarkCoreExtension());
+
+// Add this extension
+$environment->addExtension(new TaskListExtension());
+
+// Instantiate the converter engine and start converting some Markdown!
+$converter = new MarkdownConverter($environment);
+
+$markdown = <<<EOT
+ - [x] Install this extension
+ - [ ] ???
+ - [ ] Profit!
+EOT;
+
+echo $converter->convert($markdown);
+
+ +

Please note that this extension doesn’t provide any JavaScript functionality to handle people checking and unchecking boxes - you’ll need to implement that yourself if needed.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/index.html b/2.5/index.html new file mode 100644 index 0000000000..b3f5173be3 --- /dev/null +++ b/2.5/index.html @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + Overview - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

+ +

Overview

+ +

Author +Latest Version +Total Downloads +Software License +Build Status +Coverage Status +Quality Score

+ +

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+ +

Installation

+ +

This library can be installed via Composer:

+ +
composer require league/commonmark
+
+ +

See the installation section for more details.

+ +

Basic Usage

+ +

Simply instantiate the converter and start converting some Markdown to HTML!

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello, World!')->getContent();
+
+// <h1>Hello, World!</h1>
+
+ +

+Important: See the basic usage and security sections for important details.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/installation/index.html b/2.5/installation/index.html new file mode 100644 index 0000000000..4fbd599f71 --- /dev/null +++ b/2.5/installation/index.html @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + Installation - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Installation

+ +

The recommended installation method is via Composer.

+ +
composer require "league/commonmark:^2.5"
+
+ +

Ensure that you’ve set up your project to autoload Composer-installed packages.

+ +

Versioning

+ +

SemVer will be followed closely. It’s highly recommended that you use Composer’s caret operator to ensure compatibility; for example: ^2.5. This is equivalent to >=2.5 <3.0.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/security/index.html b/2.5/security/index.html new file mode 100644 index 0000000000..ff4baae79c --- /dev/null +++ b/2.5/security/index.html @@ -0,0 +1,499 @@ + + + + + + + + + + + + + + + + + Security - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Security

+ +

In order to be fully compliant with the CommonMark spec, certain security settings are disabled by default. You will want to configure these settings if untrusted users will be providing the Markdown content:

+ + + +

Further information about each option can be found below.

+ +

HTML Input

+ +

All HTML input is unescaped by default. This behavior ensures that league/commonmark is 100% compliant with the CommonMark spec.

+ +

If you’re developing an application which renders user-provided Markdown from potentially untrusted users, you are strongly encouraged to set the html_input option in your configuration to either escape or strip:

+ +

Example - Escape all raw HTML input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// &lt;script&gt;alert("Hello XSS!");&lt;/script&gt;
+
+ +

Example - Strip all HTML from the input

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'strip']);
+echo $converter->convert('<script>alert("Hello XSS!");</script>');
+
+// (empty output)
+
+ +

Failing to set this option could make your site vulnerable to cross-site scripting (XSS) attacks!

+ +

See the configuration section for more information.

+ + + +

Unsafe links are also allowed by default due to CommonMark spec compliance. An unsafe link is one that uses any of these protocols:

+ + + +

To prevent these from being parsed and rendered, you should set the allow_unsafe_links option to false.

+ +

Nesting Level

+ +

No maximum nesting level is enforced by default. Markdown content which is too deeply-nested (like 10,000 nested blockquotes: ‘> > > > > …’) could result in long render times or segfaults.

+ +

If you need to parse untrusted input, consider setting a reasonable max_nesting_level (perhaps 10-50) depending on your needs. Once this nesting level is hit, any subsequent Markdown will be rendered as plain text.

+ +

Example - Prevent deep nesting

+ +
use League\CommonMark\CommonMarkConverter;
+
+$markdown = str_repeat('> ', 10000) . ' Foo';
+
+$converter = new CommonMarkConverter(['max_nesting_level' => 5]);
+echo $converter->convert($markdown);
+
+// <blockquote>
+//   <blockquote>
+//     <blockquote>
+//       <blockquote>
+//         <blockquote>
+//           <p>&gt; &gt; &gt; &gt; &gt; &gt; &gt; ... Foo</p></blockquote>
+//       </blockquote>
+//     </blockquote>
+//   </blockquote>
+// </blockquote>
+
+ +

See the configuration section for more information.

+ +

Additional Filtering

+ +

Although this library does offer these security features out-of-the-box, some users may opt to also run the HTML output through additional filtering layers (like HTMLPurifier). If you do this, make sure you thoroughly test your additional post-processing steps and configure them to work properly with the types of HTML elements and attributes that converted Markdown might produce, otherwise, you may end up with weird behavior like missing images, broken links, mismatched HTML tags, etc.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/support/index.html b/2.5/support/index.html new file mode 100644 index 0000000000..d09ab1e327 --- /dev/null +++ b/2.5/support/index.html @@ -0,0 +1,431 @@ + + + + + + + + + + + + + + + + + Support - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Support

+ +

Here are some useful resources to help you use this project:

+ + + +

Supported Versions

+ +

See our security policy for information about the support cycle for bug fixes and security updates.

+ +

Reporting a Vulnerability

+ +

If you discover a security vulnerability within this package, please use the Tidelift security contact form or email Colin O’Dell at colinodell@gmail.com. All security vulnerabilities will be promptly addressed. Please do not disclose security-related issues publicly until a fix has been announced!

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/upgrading/index.html b/2.5/upgrading/index.html new file mode 100644 index 0000000000..b3e9688c27 --- /dev/null +++ b/2.5/upgrading/index.html @@ -0,0 +1,415 @@ + + + + + + + + + + + + + + + + + Upgrading from 2.4 to 2.5 - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

Upgrading from 2.4 to 2.5

+ +

These are no significant changes since 2.4.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/2.5/xml/index.html b/2.5/xml/index.html new file mode 100644 index 0000000000..ae70ebff2e --- /dev/null +++ b/2.5/xml/index.html @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + XML Rendering - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + + + + + + + + + + +
+
+ + + + + + +

XML Rendering

+ +

Version 2.0 introduced the ability to render Markdown Document objects in XML. This is particularly useful for debugging custom extensions as you can see the XML representation of the Abstract Syntax Tree.

+ +

To convert Markdown to XML, you would instantiate a MarkdownToXmlConverter with an Environment and then call convert() on any Markdown.

+ +
use League\CommonMark\Environment\Environment;
+use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
+use League\CommonMark\Xml\MarkdownToXmlConverter;
+
+$environment = new Environment();
+$environment->addExtension(new CommonMarkCoreExtension());
+
+$converter = new MarkdownToXmlConverter($environment);
+
+echo $converter->convert('# **Hello** World!');
+
+ +

This will display XML output like this:

+ +
<?xml version="1.0" encoding="UTF-8"?>
+<document xmlns="http://commonmark.org/xml/1.0">
+    <heading level="1">
+        <strong>
+            <text>Hello</text>
+        </strong>
+        <text> World!</text>
+    </heading>
+</document>
+
+ +

Alternatively, if you already have a Document object you want to visualize in XML, you can use theXmlRenderer class to convert it to XML.

+ +

Return Value

+ +

Like with CommonMarkConverter::convert(), the renderDocument() actually returns an instance of League\CommonMark\Output\RenderedContentInterface. You can cast this (implicitly, as shown above, or explicitly) to a string or call getContent() to get the final XML output.

+ +

Customizing the XML Output

+ +

See the rendering documentation for information on customizing the XML output.

+ + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/CNAME b/CNAME new file mode 100644 index 0000000000..e270d80a30 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +commonmark.thephpleague.com diff --git a/README.md b/README.md new file mode 100644 index 0000000000..9b7795d060 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + +# Don't commit to this branch! + + +This branch is automatically generated by Jekyll via GitHub Actions. + +To make changes, please go back to the `main` branch and make changes within the `docs` folder. diff --git a/basic-usage/index.html b/basic-usage/index.html new file mode 100644 index 0000000000..7476744f89 --- /dev/null +++ b/basic-usage/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/changelog/index.html b/changelog/index.html new file mode 100644 index 0000000000..81d1283703 --- /dev/null +++ b/changelog/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/command-line/index.html b/command-line/index.html new file mode 100644 index 0000000000..69de29422d --- /dev/null +++ b/command-line/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/configuration/index.html b/configuration/index.html new file mode 100644 index 0000000000..b3c6c3ce4d --- /dev/null +++ b/configuration/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/custom.css b/custom.css new file mode 100644 index 0000000000..c44a81c06a --- /dev/null +++ b/custom.css @@ -0,0 +1,430 @@ +html { + background:#f2f7fc; +} + +body { + min-width: 320px; + display: flex; + flex-flow: column; +} + +blockquote { + border-left: 4px solid #ccc; + font-style:italic; + box-sizing: border-box; + padding:0 10px; +} + +header { + position:fixed; + height:4.5em; + z-index: 1; + border-bottom:1px solid #cfe4f9; + max-width: none; + width: 100%; + padding:0; + margin:0; + background:#fff; +} + +header .header-content:after { + content: ""; + display: table; + clear: both; +} + +header .title { + float: left; + text-align:left; + font-family: "Museo 100", sans-serif; + font-weight: bold; + margin:0; + padding:0; + width:400px; +} + +header .title a { + color:#ff4143; + text-decoration: none; +} + +header .search { + float:left; + text-align:right; + width:calc(100% - 480px); + padding-right:.3em; +} + +.banner { + max-width: 100%; +} + +#doc-search { + font-family: "Museo Sans 500", sans-serif; + font-weight: normal; + font-size: 16px; + border:1px solid #e8e8e8; + background-color:#f4f4f4; + padding:.5em 1em; + margin-left:.3em; + border-radius: .3em; +} + +header .versions { + float:left; + display:none; + font-family: "Museo Sans 500", sans-serif; + font-weight: normal; +} + +header .versions h2 { + font-family: "Museo Sans 500", sans-serif; + font-weight: normal; + font-size: 16px; + background:#1672ce; + color:#fff; + margin:0; + width: 75px; + text-align: center; + border-radius: .3em; + margin-bottom:.4em; + padding:.5em .3em; + cursor: pointer; + transition: 0.3s; +} + +header .versions h2:hover { + background: #0a64bf; +} + +header .versions ul { + display:none; + margin:0; + padding:0; + list-style:none; + width: 75px; +} + +header .versions .show { + display:block; +} + +header .versions li { + margin:0; + padding:0; + text-align: center; +} + +header .versions a { + display:block; + margin:0; + padding:.5em .3em; + text-decoration:none; + color:#1672ce; + background: #fff; + border:solid #c7c7c7; + border-width:0 1px 1px; +} + +header .versions a:hover { + background:#f1f1f1; +} + +header .versions li:first-of-type a { + border-top-width: 1px; + border-radius:.3em .3em 0 0; +} + +header .versions li:last-of-type a { + border-radius:0 0 .3em .3em; +} + +label[for=menu] { + position:fixed; + z-index: 2; + top:20px; + right:0; + display:inline-block; + box-sizing: border-box; + background:transparent; + color:#1672ce; + width:50px; + font-size:30px; + line-height: 1; + padding:0; + margin:0; +} + +label[for=menu]:hover { + background:transparent; + color:#1672ce; +} + +main { + padding-top:4em; + background:none; +} + +/* ---------- header automatic permalink -----------*/ + +.header-permalink { + text-decoration: none; + color:transparent; + font-size:.8em; + vertical-align: super; +} + +.header-permalink:hover, +h1:hover .header-permalink, +h2:hover .header-permalink, +h3:hover .header-permalink, +h4:hover .header-permalink, +h5:hover .header-permalink { + text-decoration: none; + color:#777; +} + +h4 { + font-variant: small-caps; + font-size:1em; +} + +main article p { + max-width: 840px; +} + +main article a { + color:#1672ce; +} + +main article p code, +main article li code, +main article div > code { + font-family: Consolas,Monaco,'Andale Mono',monospace; + font-size: 17px; + line-height: 100%; + color:#1672ce; + background: #fff; + border:none; +} + +main article p img { + box-sizing: border-box; + margin:.3em; + padding:0; + display: block; +} + +main article p a img { + box-sizing: border-box; + margin:0; + padding:0; + display:inline; +} + +main article hr { + border: 1px solid #d9e0e6; +} + +footer { + border-top:1px solid #cfe4f9; + background:#fff; + max-width: none; + text-align:center; + color:#a1a1a1; +} + +footer span a { + color:#007ec6; +} + +main menu .menu-section { + border-bottom:1px dashed #cfe4f9; + padding-bottom:1em; +} + +main menu .menu-section:last-of-type { + border-bottom:none; +} + +main menu h2 { + margin-top:1.5em; + padding-left:.7em; + color:#2b3d50; + font-size:1em; + font-weight: bold; + text-transform: none; + box-shadow: none; +} + +main menu ul li a { + border-radius:.1em; + font-size:1em; + margin:.2em; + padding:.6em; + color:#1672ce; +} + +main menu ul li a:hover { + color:#1672ce; + padding:.6em; + background:transparent; + text-decoration: underline; +} + +main menu ul li.selected { + background: none; +} + +main menu ul li.selected a { + color:#fff; + background:#1672ce; + padding:.6em; +} + +main menu ul li.selected a:hover { + text-decoration: none; +} + +pre { + border-width:0 0 0 4px; + background: #fff; + width: fit-content; + max-width: 100%; +} + +main article table { + width: initial; + max-width: 100%; +} + +table { + border:1px solid #eee; + background: #fff; + box-shadow:0 6px 6px 0 rgba(80, 88, 94, .24); +} + +table th, +table th > * { + color:#fff; + background: #1672ce; +} + +@media screen and (max-width: 420px) { + table { + display: flex; + flex-direction: column; + justify-content: space-between; + font-size: 0.9rem; + } +} + +@media screen and (max-width: 375px) { + main article table td { + padding: 2px 5px 2px 2px; + } + thead tr { + font-size: 0.8rem; + } +} + +header .logo .name { + font-size: 1.6rem; + line-height: 100%; + margin: 0 !important; +} + +@media screen and (min-width: 768px) { + header .logo .name { + font-size: 2.5rem; + } +} + +@media screen and (min-width: 1024px) { + header .logo .name { + font-size: 3rem; + } +} + +header .logo em { + color: #777; + font-style: normal; +} + +@media screen and (max-width: 549px) { + header { + padding: 25px 0 20px 10px; + } + + menu { + text-align: center; + } + + header .logo { + text-align: left; + } +} + +@media screen and (min-width: 550px) { + header { + background:#fff; + } + + header .header-content { + box-sizing: border-box; + padding:1em; + } + + header .versions { + display: block; + } + + label[for=menu] { + display:none; + } + + main { + background: none; + } + + main menu { + border-right: 1px dashed #cfe4f9; + } + + main menu .versions-small { + display:none; + } + + main article p, + main article li { + font-size:.9em; + } +} + +@media screen and (max-width: 750px) { + #doc-search { + display: none; + } +} + +@media screen and (min-width: 850px) { + main article { + max-width: none; + } +} + +h2 code { + font-size: 0.8em; +} + +.features ul { + list-style-type: none; +} + +:target:before { + content: ' '; + display: block; + padding-top: 100px; + margin-top: -100px; + visibility: hidden; +} diff --git a/custom.js b/custom.js new file mode 100644 index 0000000000..a84d855e95 --- /dev/null +++ b/custom.js @@ -0,0 +1,18 @@ +(() => { + + const uri = new URL(location.href); + + document.querySelector('header nav h2').addEventListener('click', function () { + this.parentNode.querySelector('ul').classList.toggle('show'); + }, false); + + document.querySelectorAll("main h2[id]").forEach((header) => { + uri.hash = header.id; + let link = document.createElement("a"); + link.className = "header-permalink"; + link.title = "Permalink"; + link.href = uri.toString(); + link.innerHTML = "¶"; + header.appendChild(link); + }); +})(); \ No newline at end of file diff --git a/customization/abstract-syntax-tree/index.html b/customization/abstract-syntax-tree/index.html new file mode 100644 index 0000000000..1274f5275c --- /dev/null +++ b/customization/abstract-syntax-tree/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/block-parsing/index.html b/customization/block-parsing/index.html new file mode 100644 index 0000000000..70a69aefa7 --- /dev/null +++ b/customization/block-parsing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/block-rendering/index.html b/customization/block-rendering/index.html new file mode 100644 index 0000000000..f266b31e1d --- /dev/null +++ b/customization/block-rendering/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/configuration/index.html b/customization/configuration/index.html new file mode 100644 index 0000000000..8a7ed07244 --- /dev/null +++ b/customization/configuration/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/cursor/index.html b/customization/cursor/index.html new file mode 100644 index 0000000000..804ea6f6b9 --- /dev/null +++ b/customization/cursor/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/delimiter-processing/index.html b/customization/delimiter-processing/index.html new file mode 100644 index 0000000000..91fdca3242 --- /dev/null +++ b/customization/delimiter-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/disabling-features/index.html b/customization/disabling-features/index.html new file mode 100644 index 0000000000..26e5f85a07 --- /dev/null +++ b/customization/disabling-features/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/document-processing/index.html b/customization/document-processing/index.html new file mode 100644 index 0000000000..07c45afabb --- /dev/null +++ b/customization/document-processing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/environment/index.html b/customization/environment/index.html new file mode 100644 index 0000000000..da65b028c5 --- /dev/null +++ b/customization/environment/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/event-dispatcher/index.html b/customization/event-dispatcher/index.html new file mode 100644 index 0000000000..07c45afabb --- /dev/null +++ b/customization/event-dispatcher/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/extensions/index.html b/customization/extensions/index.html new file mode 100644 index 0000000000..d2f3151b4e --- /dev/null +++ b/customization/extensions/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/index.html b/customization/index.html new file mode 100644 index 0000000000..e4e65875c6 --- /dev/null +++ b/customization/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/inline-parsing/index.html b/customization/inline-parsing/index.html new file mode 100644 index 0000000000..88d4c036e5 --- /dev/null +++ b/customization/inline-parsing/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/inline-rendering/index.html b/customization/inline-rendering/index.html new file mode 100644 index 0000000000..f266b31e1d --- /dev/null +++ b/customization/inline-rendering/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/overview/index.html b/customization/overview/index.html new file mode 100644 index 0000000000..e4e65875c6 --- /dev/null +++ b/customization/overview/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/customization/slug-normalizer/index.html b/customization/slug-normalizer/index.html new file mode 100644 index 0000000000..7c2c0bade6 --- /dev/null +++ b/customization/slug-normalizer/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/attributes/index.html b/extensions/attributes/index.html new file mode 100644 index 0000000000..8a19c4c27f --- /dev/null +++ b/extensions/attributes/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/autolinks/index.html b/extensions/autolinks/index.html new file mode 100644 index 0000000000..40ee2c88fa --- /dev/null +++ b/extensions/autolinks/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/commonmark/index.html b/extensions/commonmark/index.html new file mode 100644 index 0000000000..d22c206312 --- /dev/null +++ b/extensions/commonmark/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/default-attributes/index.html b/extensions/default-attributes/index.html new file mode 100644 index 0000000000..7e55da36e7 --- /dev/null +++ b/extensions/default-attributes/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/description-lists/index.html b/extensions/description-lists/index.html new file mode 100644 index 0000000000..71d5171eb6 --- /dev/null +++ b/extensions/description-lists/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/disallowed-raw-html/index.html b/extensions/disallowed-raw-html/index.html new file mode 100644 index 0000000000..f42d4a3bbd --- /dev/null +++ b/extensions/disallowed-raw-html/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/embed/index.html b/extensions/embed/index.html new file mode 100644 index 0000000000..11ae010e04 --- /dev/null +++ b/extensions/embed/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/external-links/index.html b/extensions/external-links/index.html new file mode 100644 index 0000000000..1306e829b1 --- /dev/null +++ b/extensions/external-links/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/footnotes/index.html b/extensions/footnotes/index.html new file mode 100644 index 0000000000..068ac387e7 --- /dev/null +++ b/extensions/footnotes/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/front-matter/index.html b/extensions/front-matter/index.html new file mode 100644 index 0000000000..09a3fd0161 --- /dev/null +++ b/extensions/front-matter/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/github-flavored-markdown/index.html b/extensions/github-flavored-markdown/index.html new file mode 100644 index 0000000000..2485fab767 --- /dev/null +++ b/extensions/github-flavored-markdown/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/heading-permalinks/index.html b/extensions/heading-permalinks/index.html new file mode 100644 index 0000000000..51174b99db --- /dev/null +++ b/extensions/heading-permalinks/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/index.html b/extensions/index.html new file mode 100644 index 0000000000..ee7b54abc7 --- /dev/null +++ b/extensions/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/inlines-only/index.html b/extensions/inlines-only/index.html new file mode 100644 index 0000000000..c7650c664a --- /dev/null +++ b/extensions/inlines-only/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/mentions/index.html b/extensions/mentions/index.html new file mode 100644 index 0000000000..2e73b7b17f --- /dev/null +++ b/extensions/mentions/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/overview/index.html b/extensions/overview/index.html new file mode 100644 index 0000000000..ee7b54abc7 --- /dev/null +++ b/extensions/overview/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/smart-punctuation/index.html b/extensions/smart-punctuation/index.html new file mode 100644 index 0000000000..5dc243479c --- /dev/null +++ b/extensions/smart-punctuation/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/strikethrough/index.html b/extensions/strikethrough/index.html new file mode 100644 index 0000000000..550372e601 --- /dev/null +++ b/extensions/strikethrough/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/table-of-contents/index.html b/extensions/table-of-contents/index.html new file mode 100644 index 0000000000..20e9e35257 --- /dev/null +++ b/extensions/table-of-contents/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/tables/index.html b/extensions/tables/index.html new file mode 100644 index 0000000000..628ba85885 --- /dev/null +++ b/extensions/tables/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/extensions/task-lists/index.html b/extensions/task-lists/index.html new file mode 100644 index 0000000000..5f0011f61d --- /dev/null +++ b/extensions/task-lists/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/global.css b/global.css new file mode 100644 index 0000000000..984a5017f2 --- /dev/null +++ b/global.css @@ -0,0 +1,42 @@ +.btn { + padding: .5rem 1rem; + margin-right: .25rem; + text-align: center; + border-radius: .25rem; + color: inherit; + text-decoration: inherit; + transition: 0.3s; +} + +.btn-block { + display: block; + width: auto; +} + +.btn-sm { + padding: .3rem .6rem; + font-size: .8rem; +} + +.btn-black { + background-color: #222222; + color: #ffffff; +} +.btn-black:hover { + background-color: #333; + color: #ffffff; +} + +.btn-pink { + background-color: #d53f8c; +} +.btn-pink:hover { + background-color: #d62b83; +} + +.btn-green { + background-color: #38a169; +} +.btn-green:hover { + background-color: #28a160; +} diff --git a/homepage.css b/homepage.css new file mode 100644 index 0000000000..cb7fc12c0e --- /dev/null +++ b/homepage.css @@ -0,0 +1,381 @@ +blockquote { + border-left: 4px solid #ccc; + font-style:italic; + box-sizing: border-box; + padding:0 10px; +} + +footer { + text-align: center; + color:#fff; +} + +pre { + border-width:0 0 0 4px; + background: #fff; +} + +main p code, +main li code, +main div > code { + font-family: Consolas,Monaco,'Andale Mono',monospace; + font-size: 17px; + line-height: 100%; + color:#1672ce; + background: #fff; + border:none; +} +/* -------- homepage css -----------------*/ + +.homepage header { + margin:0 auto; + padding:0 0 3em; + box-sizing: border-box; + background:#19242F url(//thephpleague.com/img/header_bg.png) no-repeat top center; + background-size: cover; + max-width: none; + color:#fff; + font-family: "Museo 300", sans-serif; +} + +.homepage header h1 { + margin:.3em auto; + font-family: "Museo 300", sans-serif; + line-height: 250%; + font-weight: normal; +} + +.homepage header h2 { + margin:0 auto; + font-family: "Museo 300", sans-serif; + color:#ff4043; + font-size:36px; + line-height:1.33; + font-weight:normal; +} + +.homepage .badge-list { + background: #fff; + padding: 3em 0 0 0; + text-align: center; +} + +.homepage .composer span { + padding:.3em 1em; + background-color:rgba(0, 0, 0, .3); + color:#fff; + font-size:.9rem; + font-family: Consolas, Monaco ,'Andale Mono', monospace; + line-height: 140%; + text-align: left; + white-space: pre; + word-wrap: normal; + word-spacing: normal; + hyphens: none; + display:inline-block; + border-radius: .3em; +} + +.homepage .hot-links { + margin:0 auto; + padding:0; + list-style:none; + width:300px; + display:flex; + align-content: top; + align-items: center; +} + +.homepage .hot-links li { + padding:0; + margin:0; +} + +.homepage .hot-links a { + display:block; + margin:0; + padding:1em; + width:150px; + border-radius:2px 0 0 2px; + text-decoration:none; + text-align:center; + font-weight:bold; + background:#fff; + color:#ff4043; +} + +.homepage .hot-links :last-child a { + border-radius:0 2px 2px 0; + background:#ff4043; + color:#fff; +} + +.homepage .hot-links:hover :last-child a { + color:#ff4043; +} + +.homepage .hot-links:hover a { + background:#fff; + color:#ff4043; +} + +.homepage .hot-links:hover a:hover { + background: #ff4043; + color: #fff; +} + +.homepage main { + color: #2b3d50; + font-family: "Museo 300", sans-serif; + line-height: 160%; + font-weight: normal; + background:#19242f; + width:auto; + right:auto; +} + +.homepage main > div { + margin:0 auto; + padding:3em 0; + box-sizing: border-box; +} + +.inner-content { + margin:0 auto; + padding:1em; + box-sizing: border-box; + text-align:center; +} + +.inner-content h1 { + color:#fff; + font-size:50px; + line-height:100%; + font-weight:normal; + font-family:"Museo Sans 300", sans-serif; + text-transform:uppercase; + margin:0; +} + +.inner-content:after { + content: ''; + display:table; + clear:both; +} + +.projects, +.sponsors { + color: #fff; +} + +.projects h2, +.sponsors h2 { + font-size:50px; + line-height:100%; + font-weight:normal; + font-family:"Museo Sans 300", sans-serif; + text-transform:uppercase; + margin: 0 0 1em 0; +} + +.project-logos { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; +} + +.project-logos a { + display: block; + object-fit: contain; + margin: 0 16px; +} + +.project-logos img { + height: 70px; + max-width: 180px; +} + +.sponsors a { + color: #3399ff; +} +.sponsors ul { + list-style: none; + font-size: 1.1em; +} + +.features { + background: #F2F7FC; + border-bottom:1px solid #CFE4F9; + color:#666; + line-height: 1.5; + font-weight: normal; + font-variant: normal; + font-style: normal; + font-size: 18px; + font-family: "Museo 300", sans-serif; +} + +.features h1 { + color:#6abcdd; +} + +.features h2 { + color:#6abcdd; + font-weight: normal; +} + +.features p { + text-align: center; +} + +.features a { + color:#6abcdd; +} + +.highlights { + background:#fff; + border-bottom:1px solid #CFE4F9; +} + +.highlights .description { + color:#666; + line-height: 1.5; + font-weight: normal; + font-variant: normal; + font-style: normal; + font-size: 18px; + font-family: "Museo 300", sans-serif; + text-align: left; +} + +.highlights h1 { + color:#ff4043; + font-size: 36px; + line-height:115%; +} + +.highlights ol { + margin:0; + text-align:left; +} + +.highlights li { + margin:0 0 15px 0; + color:#666; + font-size:16px; + font-weight:bold; +} + +.highlights li p { + margin:0; + line-height: 1.4; + font-weight: normal; + font-variant: normal; + font-style: normal; + font-size: 18px; + font-family: "Museo 300", sans-serif; + color:#ff4043; +} + +.highlights a { + color:#ff4043; +} + +.questions { + padding:0; + background:#fff; + color:#666; + border-bottom:1px solid #CFE4F9; +} + +.questions h1 { + font-size:36px; + color:#ff4043; +} + +.questions a { + color:#6abcdd; +} + +.questions a:hover { + text-decoration: none; +} + +@media screen and (max-width: 549px) { + .homepage header h1 { + margin:0 auto; + font-size:clamp(1.8rem, 5.9vw, 42px); + } + + .homepage .composer span { + font-size:1rem; + } +} + +@media screen and (min-width: 549px) { + .homepage header h1 { + margin:0 auto; + font-size:clamp(1.8rem, 5.9vw, 96px); + } + + .inner-content { + max-width:1000px; + } + + .homepage main { + width:initial; + right:initial; + } + + .highlights h1 { + font-size: 50px; + } + + .highlights li { + font-size:24px; + } + + .highlights li p { + font-size:20px; + } + + .highlights .column { + float:left; + width:45%; + } + + .highlights .one { + margin:0 10% 0 0; + } + + .documentation h1 { + font-size:50px; + } +} + +@media screen and (min-width:700px) { + .documentation .version { + float:left; + width:42%; + margin:2%; + max-width:289px; + } +} + +@media screen and (min-width: 910px) { + .documentation .version { + float:left; + width:30%; + margin:1%; + } + + .homepage header h1 { + margin:0 auto; + font-size:clamp(1.8rem, 5.9vw, 96px); + } +} + +#sponsors + p + ul { + list-style-type: none; +} diff --git a/images/commonmark-banner.png b/images/commonmark-banner.png new file mode 100644 index 0000000000..5ccbd149ff Binary files /dev/null and b/images/commonmark-banner.png differ diff --git a/images/commonmark-social.png b/images/commonmark-social.png new file mode 100644 index 0000000000..9d8d21040e Binary files /dev/null and b/images/commonmark-social.png differ diff --git a/images/users/cachet.svg b/images/users/cachet.svg new file mode 100644 index 0000000000..9b8563fc12 --- /dev/null +++ b/images/users/cachet.svg @@ -0,0 +1,16 @@ + + + + Cachet + Created with Sketch. + + + + + + + + + + + diff --git a/images/users/daux.png b/images/users/daux.png new file mode 100644 index 0000000000..42979d4b2e Binary files /dev/null and b/images/users/daux.png differ diff --git a/images/users/drupal.svg b/images/users/drupal.svg new file mode 100755 index 0000000000..7d777cab6b --- /dev/null +++ b/images/users/drupal.svg @@ -0,0 +1 @@ +Risorsa 81 \ No newline at end of file diff --git a/images/users/laravel.svg b/images/users/laravel.svg new file mode 100644 index 0000000000..ebe99bb2fc --- /dev/null +++ b/images/users/laravel.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + diff --git a/images/users/neos.svg b/images/users/neos.svg new file mode 100644 index 0000000000..98e790191e --- /dev/null +++ b/images/users/neos.svg @@ -0,0 +1 @@ +neos_avatar_primary \ No newline at end of file diff --git a/images/users/twig.svg b/images/users/twig.svg new file mode 100644 index 0000000000..5d977dc426 --- /dev/null +++ b/images/users/twig.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000000..9589229438 --- /dev/null +++ b/index.html @@ -0,0 +1,218 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+ +

+
+
+ +
+
+ Author + Latest Version + Total Downloads + Software License + Build Status + Coverage Status + Quality Score +
+
+
+
+

Highlights

+
+

The PHP CommonMark parser is a robust, highly-extensible Markdown parser for PHP based on the CommonMark and GitHub-Flavored Markdown specifications.

+
+
+
+
    + +
  1. The only PHP library fully compatible with the CommonMark and GitHub-Flavored Markdown specs

  2. + +
  3. Highly extensible architecture supports custom syntax and other customizations

  4. + +
  5. Community extensions and integrations for popular frameworks and CMSes

  6. + +
  7. Easy-to-use API

  8. + +
+
+
+
+ +
+
+

Used By

+ +
+
+ +
+
+ + + + +

Features

+ +

Easy Usage

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter();
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Security

+ +

All CommonMark features are supported by default, including raw HTML and unsafe links, which you may want to disable using the html_input and allow_unsafe_links options:

+ +
use League\CommonMark\CommonMarkConverter;
+
+$converter = new CommonMarkConverter(['html_input' => 'escape', 'allow_unsafe_links' => false]);
+echo $converter->convert('# Hello World!');
+
+// <h1>Hello World!</h1>
+
+ +

Included Extensions

+ +

This project includes several built-in extensions you can use to enable additional features and syntax.

+ +

Customization

+ +

This library allows you to add custom syntax, renderers, and more. Check out the Customization section for more information.

+ +

Community Integrations & Extensions

+ +

An updated list of pre-built integrations and extensions can be found in the Related Packages section of the README.

+ +
+
+ +
+
+

Sponsors

+

We'd 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! +

+
+
+ +
+
+

Questions?

+

league/commonmark was created by Colin O'Dell. Find him on Twitter at @colinodell.

+
+
+ + +
+ + + + + + diff --git a/installation/index.html b/installation/index.html new file mode 100644 index 0000000000..272dd533c0 --- /dev/null +++ b/installation/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/redirects.json b/redirects.json new file mode 100644 index 0000000000..21576bac81 --- /dev/null +++ b/redirects.json @@ -0,0 +1 @@ +{"/0.20/customization/abstract-syntax-tree/":"http://commonmark.thephpleague.com/1.0/customization/abstract-syntax-tree/","/customization/abstract-syntax-tree/":"http://commonmark.thephpleague.com/2.5/customization/abstract-syntax-tree/","/extensions/attributes/":"http://commonmark.thephpleague.com/2.4/extensions/attributes/","/extensions/autolinks/":"http://commonmark.thephpleague.com/2.4/extensions/autolinks/","/basic-usage/":"http://commonmark.thephpleague.com/2.5/basic-usage/","/0.20/basic-usage/":"http://commonmark.thephpleague.com/1.0/basic-usage/","/customization/block-parsing/":"http://commonmark.thephpleague.com/2.4/customization/block-parsing/","/0.20/customization/block-parsing/":"http://commonmark.thephpleague.com/1.0/customization/block-parsing/","/0.20/customization/block-rendering/":"http://commonmark.thephpleague.com/1.0/customization/block-rendering/","/changelog/":"http://commonmark.thephpleague.com/releases/","/0.20/changelog/":"http://commonmark.thephpleague.com/1.0/changelog/","/0.20/command-line/":"http://commonmark.thephpleague.com/1.0/command-line/","/command-line/":"http://commonmark.thephpleague.com/1.6/command-line/","/extensions/commonmark/":"http://commonmark.thephpleague.com/2.5/extensions/commonmark/","/configuration/":"http://commonmark.thephpleague.com/2.4/configuration/","/customization/configuration/":"http://commonmark.thephpleague.com/2.4/customization/configuration/","/0.20/configuration/":"http://commonmark.thephpleague.com/1.0/configuration/","/0.20/customization/cursor/":"http://commonmark.thephpleague.com/1.0/customization/cursor/","/customization/cursor/":"http://commonmark.thephpleague.com/2.4/customization/cursor/","/extensions/default-attributes/":"http://commonmark.thephpleague.com/2.5/extensions/default-attributes/","/customization/delimiter-processing/":"http://commonmark.thephpleague.com/2.5/customization/delimiter-processing/","/0.20/customization/delimiter-processing/":"http://commonmark.thephpleague.com/1.0/customization/delimiter-processing/","/extensions/description-lists/":"http://commonmark.thephpleague.com/2.4/extensions/description-lists/","/customization/disabling-features/":"http://commonmark.thephpleague.com/2.4/customization/disabling-features/","/extensions/disallowed-raw-html/":"http://commonmark.thephpleague.com/2.5/extensions/disallowed-raw-html/","/extensions/embed/":"http://commonmark.thephpleague.com/2.5/extensions/embed/","/0.20/customization/environment/":"http://commonmark.thephpleague.com/1.0/customization/environment/","/customization/environment/":"http://commonmark.thephpleague.com/2.5/customization/environment/","/1.5/customization/document-processing/":"http://commonmark.thephpleague.com/1.5/customization/event-dispatcher/","/1.4/customization/document-processing/":"http://commonmark.thephpleague.com/1.4/customization/event-dispatcher/","/customization/document-processing/":"http://commonmark.thephpleague.com/2.4/customization/event-dispatcher/","/customization/event-dispatcher/":"http://commonmark.thephpleague.com/2.4/customization/event-dispatcher/","/0.20/customization/document-processing/":"http://commonmark.thephpleague.com/1.0/customization/event-dispatcher/","/1.0/customization/document-processing/":"http://commonmark.thephpleague.com/1.0/customization/event-dispatcher/","/1.3/customization/document-processing/":"http://commonmark.thephpleague.com/1.3/customization/event-dispatcher/","/customization/extensions/":"http://commonmark.thephpleague.com/2.5/customization/extensions/","/0.20/customization/extensions/":"http://commonmark.thephpleague.com/1.0/customization/extensions/","/extensions/external-links/":"http://commonmark.thephpleague.com/2.5/extensions/external-links/","/extensions/footnotes/":"http://commonmark.thephpleague.com/2.4/extensions/footnotes/","/extensions/front-matter/":"http://commonmark.thephpleague.com/2.5/extensions/front-matter/","/extensions/github-flavored-markdown/":"http://commonmark.thephpleague.com/2.5/extensions/github-flavored-markdown/","/extensions/heading-permalinks/":"http://commonmark.thephpleague.com/2.5/extensions/heading-permalinks/","/0.20/":"http://commonmark.thephpleague.com/1.0/","/customization/inline-parsing/":"http://commonmark.thephpleague.com/2.5/customization/inline-parsing/","/0.20/customization/inline-parsing/":"http://commonmark.thephpleague.com/1.0/customization/inline-parsing/","/0.20/customization/inline-rendering/":"http://commonmark.thephpleague.com/1.0/customization/inline-rendering/","/extensions/inlines-only/":"http://commonmark.thephpleague.com/2.4/extensions/inlines-only/","/installation/":"http://commonmark.thephpleague.com/2.4/installation/","/0.20/installation/":"http://commonmark.thephpleague.com/1.0/installation/","/extensions/mentions/":"http://commonmark.thephpleague.com/2.4/extensions/mentions/","/customization/":"http://commonmark.thephpleague.com/2.5/customization/overview/","/customization/overview/":"http://commonmark.thephpleague.com/2.5/customization/overview/","/extensions/":"http://commonmark.thephpleague.com/2.5/extensions/overview/","/extensions/overview/":"http://commonmark.thephpleague.com/2.5/extensions/overview/","/0.20/customization/":"http://commonmark.thephpleague.com/1.0/customization/overview/","/0.20/customization/overview/":"http://commonmark.thephpleague.com/1.0/customization/overview/","/upgrading/":"http://commonmark.thephpleague.com/2.5/upgrading/","/upgrading/changelog/":"http://commonmark.thephpleague.com/releases/","/customization/block-rendering/":"http://commonmark.thephpleague.com/2.5/customization/rendering/","/customization/inline-rendering/":"http://commonmark.thephpleague.com/2.5/customization/rendering/","/security/":"http://commonmark.thephpleague.com/2.5/security/","/0.20/security/":"http://commonmark.thephpleague.com/1.0/security/","/customization/slug-normalizer/":"http://commonmark.thephpleague.com/2.5/customization/slug-normalizer/","/extensions/smart-punctuation/":"http://commonmark.thephpleague.com/2.5/extensions/smart-punctuation/","/extensions/strikethrough/":"http://commonmark.thephpleague.com/2.5/extensions/strikethrough/","/support/":"http://commonmark.thephpleague.com/2.5/support/","/extensions/table-of-contents/":"http://commonmark.thephpleague.com/2.5/extensions/table-of-contents/","/extensions/tables/":"http://commonmark.thephpleague.com/2.5/extensions/tables/","/extensions/task-lists/":"http://commonmark.thephpleague.com/2.5/extensions/task-lists/","/0.20/upgrading/":"http://commonmark.thephpleague.com/1.0/upgrading/","/xml/":"http://commonmark.thephpleague.com/2.5/xml/"} \ No newline at end of file diff --git a/releases/index.html b/releases/index.html new file mode 100644 index 0000000000..f5b23f5e4c --- /dev/null +++ b/releases/index.html @@ -0,0 +1,2902 @@ + + + + + + + + + + + + + + + + + Release Notes - CommonMark for PHP + + + + + + + + + + + + + + + + + + + + + + + + +
+
+

+ +

+ + +
+
+ + + + +
+ +
+

Versions

+ +
+ + + +

Upgrading Guide

+ + + +
+
+ + + + + + +

Release Notes

+ +

2.5.3 - 2024-08-16

+ +

Changed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.2…2.5.3

+ +

2.5.2 - 2024-08-14

+ +

Changed

+ + + +

Fixed

+ + + +
+ +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.1…2.5.2

+ +

2.5.1 - 2024-07-24

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.5.0…2.5.1

+ +

2.5.0 - 2024-07-22

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.4…2.5.0

+ +

2.4.4 - 2024-07-22

+ +

Fixed

+ + + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.3…2.4.4

+ +

2.4.3 - 2024-07-22

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.2…2.4.3

+ +

2.4.2 - 2024-02-02

+ +

Fixed

+ + + +

New Contributors

+ + +

Full Changelog: https://github.com/thephpleague/commonmark/compare/2.4.1…2.4.2

+ +

2.4.1 - 2023-08-30

+ +

Fixed

+ + + +

2.4.0 - 2023-03-24

+ +

See the upgrading guide for more information about the exception-related changes

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

2.3.9 - 2023-02-15

+ +

Fixed

+ + + +

2.3.8 - 2022-12-10

+ +

Fixed

+ + + +

2.3.7 - 2022-11-17

+ +

Fixed

+ + + +

2.3.6 - 2022-10-30

+ +

Fixed

+ + + +

2.3.5 - 2022-07-29

+ +

Fixed

+ + + +

2.3.4 - 2022-07-17

+ +

Changed

+ + + +

Fixed

+ + + +

2.3.3 - 2022-06-07

+ +

Fixed

+ + + +

2.3.2 - 2022-06-03

+ +

Fixed

+ + + +

2.2.5 - 2022-06-03

+ +

Fixed

+ + + +

2.3.1 - 2022-05-14

+ +

Fixed

+ + + +

2.2.4 - 2022-05-14

+ +

Fixed

+ + + +

2.3.0 - 2022-04-07

+ +

Added

+ + + +

Deprecated

+ + + +

2.2.3 - 2022-02-26

+ +

Fixed

+ + + +

2.1.3 - 2022-02-26

+ +

Fixed

+ + + +

2.0.4 - 2022-02-26

+ +

Fixed

+ + + +

2.2.2 - 2022-02-13

+ +

Fixed

+ + + +

2.1.2 - 2022-02-13

+ +

Fixed

+ + + +

2.0.3 - 2022-02-13

+ +

Fixed

+ + + +

2.2.1 - 2022-01-25

+ +

Fixed

+ + + +

Removed

+ + + +

2.2.0 - 2022-01-22

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

1.6.7 - 2022-01-13

+ +

Changed

+ + + +

2.1.1 - 2022-01-02

+ +

Added

+ + + +

2.1.0 - 2021-12-05

+ +

Added

+ + + +

Fixed

+ + + +

2.0.2 - 2021-08-14

+ +

Changed

+ + + +

Fixed

+ + + +

2.0.1 - 2021-07-31

+ +

Fixed

+ + + +

2.0.0 - 2021-07-24

+ +

No changes were introduced since the previous 2.0.0-rc2 release.

+ +

Please refer to the full Changelog for a list of all changes between 1.x and 2.0. An upgrading guide is also available.

+ +

2.0.0-rc2 - 2021-07-17

+ +

Fixed

+ + + +

1.6.6 - 2021-07-17

+ +

Fixed

+ + + +

2.0.0-rc1 - 2021-07-10

+ +

No changes were introduced since the previous release.

+ +

2.0.0-beta3 - 2021-07-03

+ +

Changed

+ + + +

2.0.0-beta2 - 2021-06-27

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

1.6.5 - 2021-06-26

+ +

Changed

+ + + +

Fixed

+ + + +

2.0.0-beta1 - 2021-06-20

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Removed

+ + + +

Deprecated

+ +

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

+ + + +

1.6.4 - 2021-06-19

+ +

Changed

+ + + +

1.6.3 - 2021-06-19

+ +

Fixed

+ + + +

1.6.2 - 2021-05-12

+ +

Fixed

+ + + +

1.6.1 - 2021-05-08

+ +

Fixed

+ + + +

1.6.0 - 2021-05-01

+ +

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

+ +

Added

+ + + +

Changed

+ + + +

Deprecated

+ + + +

Fixed

+ + + +

1.5.8 - 2021-03-28

+ +

Fixed

+ + + +

1.5.7 - 2020-10-31

+ +

Fixed

+ + + +

1.5.6 - 2020-10-17

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.5 - 2020-09-13

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.4 - 2020-08-18

+ +

Fixed

+ + + +

1.5.3 - 2020-07-19

+ +

Fixed

+ + + +

1.5.2 - 2020-07-19

+ +

Changed

+ + + +

Fixed

+ + + +

1.5.1 - 2020-06-27

+ +

Fixed

+ + + +

1.5.0 - 2020-06-21

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.4.3 - 2020-05-04

+ +

Fixed

+ + + +

1.4.2 - 2020-04-24

+ +

Fixed

+ + + +

1.4.1 - 2020-04-20

+ +

Fixed

+ + + +

1.4.0 - 2020-04-18

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.3.4 - 2020-04-13

+ +

Fixed

+ + + +

1.3.3 - 2020-04-05

+ +

Fixed

+ + + +

1.3.2 - 2020-03-25

+ +

Fixed

+ + + +

1.3.1 - 2020-02-28

+ +

Fixed

+ + + +

1.3.0 - 2020-02-09

+ +

ℹ️ Do you use league/commonmark-ext* packages? Those features are now included directly in this library! See #409 for details on making the switch.

+ +

Added

+ + + +

Changed

+ + + +

1.2.2 - 2020-01-16

+ +

This release contains the same changes as 1.1.3:

+ +

Fixed

+ + + +

1.1.3 - 2020-01-16

+ +

Fixed

+ + + +

1.2.1 - 2020-01-15

+ +

Changed

+ + + +

1.2.0 - 2020-01-09

+ +

Changed

+ + + +

1.1.2 - 2019-12-10

+ +

Fixed

+ + + +

1.1.1 - 2019-11-11

+ +

Fixed

+ + + +

1.1.0 - 2019-10-31

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

1.0.0 - 2019-06-29

+ +

First stable release! 🎉

+ +

No code changes have been introduced since 1.0.0-rc1

+ +

1.0.0-rc1 - 2019-06-20

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

0.19.3 - 2019-06-18

+ +

Fixed

+ + + +

1.0.0-beta4 - 2019-06-05

+ +

Added

+ + + +

Removed

+ + + +

1.0.0-beta3 - 2019-05-28

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta2 - 2019-05-27

+ +

This beta release fixes a couple of items that were not addressed in the previous beta.

+ +

Changed

+ + + +

Removed

+ + + +

1.0.0-beta1 - 2019-05-26

+ +

See the upgrading guide for additional information.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

Removed

+ + + +

0.19.2 - 2019-05-19

+ +

Fixed

+ + + +

0.19.1 - 2019-04-11

+ +

0.19.1 is an immediate follow-up to 0.19.0 which fixes issues with extensions that register other extensions.

+ +

(While this technically introduces a BC-break, it’s allowed under SemVer’s rules for 0.x releases and is necessary for 0.19.x code to work as expected.)

+ +

Added

+ + + +

Fixed

+ + + +

0.19.0 - 2019-04-11

+ +

The 50th release of league/commonmark is here! :tada:

+ +

The Environment and extension framework underwent some major changes in this release. Be sure to read the upgrade notes if you maintain any community extensions or have written custom functionality on top of this library.

+ +

Added

+ + + +

Changed

+ + + +

Removed

+ + + +

0.18.5 - 2019-04-09

+ +

Fixed

+ + + +

0.18.4 - 2019-03-24

+ +

Changed

+ + + +

Fixed

+ + + +

0.18.3 - 2019-03-21

+ +

This is a security update release.

+ +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ + + +

0.18.2 - 2019-03-17

+ +

Fixed

+ + + +

Deprecated

+ + + +

0.18.1 - 2018-12-30

+ +

This release contains an important security update for CVE-2018-20583.

+ +

Fixed

+ + + +

0.18.0 - 2018-09-18

+ +

No breaking changes were introduced, but we did add a new interface: ConverterInterface. Consider depending on this interface in your code instead of the concrete implementation. (See #330)

+ +

Added

+ + + +

Changed

+ + + +

0.17.5 - 2018-03-29

+ +

Fixed

+ + + +

0.17.4 - 2018-03-29

+ +

Added

+ + + +

0.17.3 - 2018-03-26

+ +

Fixed

+ + + +

0.17.2 - 2018-03-26

+ +

Added

+ + + +

Fixed

+ + + +

0.17.1 - 2018-03-18

+ +

Added

+ + + +

0.17.0 - 2017-12-30

+ +

This release contains several breaking changes and a minimum PHP version bump - see UPGRADE.md for more details.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + +

Deprecated

+ + + +

Removed

+ + + +

0.16.0 - 2017-10-31

+ +

This release contains breaking changes, several performance improvements, and two deprecations:

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ +

The following methods were deprecated and are scheduled for removal in 0.17.0 or 1.0.0 (whichever comes first). See UPGRADE.md for more information.

+ + + +

Removed

+ + + +

0.15.7 - 2017-10-26

+ +

Fixed

+ + + +

0.15.6 - 2017-08-08

+ +

Fixed

+ + + +

0.15.5 - 2017-08-05

+ +

This release bumps spec compliance to 0.28 without breaking changes to the API.

+ +

Added

+ + + +

Changed

+ + + +

Fixed

+ + + +

Deprecated

+ +

An unused constant and static method were deprecated and will be removed in a future release. See for more information.

+ + + +

0.15.4 - 2017-05-09

+ +

Added

+ + + +

Fixed

+ + + +

Deprecated

+ +

All deprecations listed here will be removed in a future 0.x release. See UPGRADE.md for instructions on preparing your code for the eventual removal of these methods.

+ + + +

0.15.3 - 2016-12-19

+ +

Fixed

+ + +

0.15.2 - 2016-11-22

+ +

Changed

+ + +

Fixed

+ + +

0.15.1 - 2016-11-08

+ +

Fixed

+ + +

0.15.0 - 2016-09-14

+ +

Added

+ + +

Changed

+ + +

Deprecated

+ + +

Fixed

+ + +

Removed

+ + +

0.14.0 - 2016-07-02

+ +

Added

+ + +

Deprecated

+ + +

0.13.4 - 2016-06-14

+ +

Fixed

+ + +

0.13.3 - 2016-05-21

+ +

Added

+ + +

0.13.2 - 2016-03-27

+ +

Added

+ + +

Changed

+ + +

0.13.1 - 2016-03-09

+ +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.13.0 - 2016-01-14

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.12.0 - 2015-11-04

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.11.3 - 2015-09-25

+ +

Fixed

+ + +

0.11.2 - 2015-09-23

+ +

Fixed

+ + +

0.11.1 - 2015-09-22

+ +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.11.0 - 2015-09-19

+ +

This release contains several major internal changes. It will likely break compatibility with custom elements, parsers, and renderers. Simple Markdown parsing is unaffected.

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.10.0 - 2015-07-25

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.9.0 - 2015-06-19

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

0.8.0 - 2015-04-29

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.7.2 - 2015-03-08

+ +

Changed

+ + +

Fixed

+ + +

0.7.1 - 2015-03-01

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

0.7.0 - 2015-02-17

+ +

Now with 50% more speed!

+ +

Added

+ + +

Changed

+ + +

Removed

+ + +

0.6.1 - 2015-01-25

+ +

Changed

+ + +

0.6.0 - 2015-01-09

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

0.5.1 - 2014-12-27

+ +

Fixed

+ + +

Removed

+ + +

0.5.0 - 2014-12-24

+ +

Added

+ + +

Changed

+ + +

Fixed

+ + +

Removed

+ + +

- 2014-12-16

+ + + + + +
+ +

+ Edit this page +

+
+ + +
+ + + + + + + + diff --git a/security/index.html b/security/index.html new file mode 100644 index 0000000000..8d69596d46 --- /dev/null +++ b/security/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/support.css b/support.css new file mode 100644 index 0000000000..d9b63217f6 --- /dev/null +++ b/support.css @@ -0,0 +1,112 @@ +.support-banner-wrapper { + position: fixed; + bottom: 0; + left: 0; + right: 0; + margin: 1rem; +} + +.support-banner { + color: #fff; + background-color: #000; + box-shadow: 0 10px 15px -3px rgba(0,0,0,.1), 0 4px 6px -2px rgba(0,0,0,.05); + border-radius: 0.5rem; + + padding: 0.5rem 1rem; + margin: 0 auto; + width: 100%; + + justify-content: space-between; + -webkit-box-pack: justify; + + align-items: center; + -webkit-box-align: center; + + display: flex; + flex-wrap: wrap; + flex-direction: row; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + + z-index: 100; +} + +@media screen and (min-width: 1200px) { + .support-banner { + max-width: 1192px; + } +} + +.support-banner-left { + width: 0; + margin: 0; + + flex: 1 1 0%; + -webkit-box-flex: 1; +} + +.support-banner-right { + display: flex; + flex-shrink: 0; + width: auto; + margin-top: 0; + + order: 2; + -webkit-box-ordinal-group: 3; + + justify-content: space-between; + -webkit-box-pack: justify; + + align-items: center; + -webkit-box-align: center; +} + +.support-banner-close { + width: 1.5rem; + margin: 0 0 0 0.5rem; + font-size: .875rem; + height: 1.5rem; + + border: none; + border-radius: 9999px; + padding: 0; + line-height: inherit; + color: inherit; + cursor: pointer; + background-color: transparent; + background-image: none; + -webkit-appearance: button; + + overflow: visible; + text-transform: none; + + display: flex; + + justify-content: center; + -webkit-box-pack: center; + + align-items: center; + -webkit-box-align: center; + + order: 3; + -webkit-box-ordinal-group: 4; +} + +.hidden { + display: none; +} + +@media (min-width: 700px) { + .sm\:inline-block { + display: inline-block; + } +} + +@media (min-width: 1060px) { + .lg\:hidden { + display: none; + } + .lg\:inline-block { + display: inline-block; + } +} diff --git a/support/index.html b/support/index.html new file mode 100644 index 0000000000..69705bbd7b --- /dev/null +++ b/support/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/upgrading/changelog/index.html b/upgrading/changelog/index.html new file mode 100644 index 0000000000..81d1283703 --- /dev/null +++ b/upgrading/changelog/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/upgrading/index.html b/upgrading/index.html new file mode 100644 index 0000000000..9a862a182e --- /dev/null +++ b/upgrading/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + + diff --git a/xml/index.html b/xml/index.html new file mode 100644 index 0000000000..2416c337e8 --- /dev/null +++ b/xml/index.html @@ -0,0 +1,51 @@ + + + + + + + + + + CommonMark for PHP - Markdown done right + + + + + + + + + + +
+
+

league/commonmark

+

Markdown done right

+

$ composer require league/commonmark

+
+
+ +
+
+
+

Redirecting…

+
+ Click here if you are not redirected. + +
+
+
+
+ + + +