{"id":13411151,"url":"https://github.com/cebe/markdown","last_synced_at":"2025-05-14T13:10:08.554Z","repository":{"id":13884329,"uuid":"16582470","full_name":"cebe/markdown","owner":"cebe","description":"A super fast, highly extensible markdown parser for PHP","archived":false,"fork":false,"pushed_at":"2022-10-04T04:54:35.000Z","size":425,"stargazers_count":1005,"open_issues_count":43,"forks_count":140,"subscribers_count":43,"default_branch":"master","last_synced_at":"2025-05-03T02:23:15.010Z","etag":null,"topics":["gfm","hacktoberfest","markdown","markdown-converter","markdown-extra","markdown-flavors","markdown-parser","markdown-to-html","php"],"latest_commit_sha":null,"homepage":"http://markdown.cebe.cc/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cebe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-06T14:58:16.000Z","updated_at":"2025-04-02T11:27:22.000Z","dependencies_parsed_at":"2022-08-31T11:50:30.929Z","dependency_job_id":null,"html_url":"https://github.com/cebe/markdown","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cebe%2Fmarkdown","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cebe%2Fmarkdown/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cebe%2Fmarkdown/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cebe%2Fmarkdown/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cebe","download_url":"https://codeload.github.com/cebe/markdown/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253360639,"owners_count":21896372,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["gfm","hacktoberfest","markdown","markdown-converter","markdown-extra","markdown-flavors","markdown-parser","markdown-to-html","php"],"created_at":"2024-07-30T20:01:11.749Z","updated_at":"2025-05-14T13:10:03.515Z","avatar_url":"https://github.com/cebe.png","language":"HTML","funding_links":[],"categories":["标记","HTML","Markdown","目录","Table of Contents","PHP","Markup","标记( Markup )","类库","标记 Markup"],"sub_categories":["标记和CSS Markup and CSS","Markup and CSS","Markup","Markdown"],"readme":"A super fast, highly extensible markdown parser for PHP\n=======================================================\n\n[![Latest Stable Version](https://poser.pugx.org/cebe/markdown/v/stable.png)](https://packagist.org/packages/cebe/markdown)\n[![Total Downloads](https://poser.pugx.org/cebe/markdown/downloads.png)](https://packagist.org/packages/cebe/markdown)\n[![Build Status](https://travis-ci.org/cebe/markdown.svg?branch=master)](http://travis-ci.org/cebe/markdown)\n[![Code Coverage](https://scrutinizer-ci.com/g/cebe/markdown/badges/coverage.png?s=db6af342d55bea649307ef311fbd536abb9bab76)](https://scrutinizer-ci.com/g/cebe/markdown/)\n[![Scrutinizer Quality Score](https://scrutinizer-ci.com/g/cebe/markdown/badges/quality-score.png?s=17448ca4d140429fd687c58ff747baeb6568d528)](https://scrutinizer-ci.com/g/cebe/markdown/)\n\nWhat is this? \u003ca name=\"what\"\u003e\u003c/a\u003e\n-------------\n\nA set of [PHP][] classes, each representing a [Markdown][] flavor, and a command line tool\nfor converting markdown files to HTML files.\n\nThe implementation focus is to be **fast** (see [benchmark][]) and **extensible**.\nParsing Markdown to HTML is as simple as calling a single method (see [Usage](#usage)) providing a solid implementation\nthat gives most expected results even in non-trivial edge cases.\n\nExtending the Markdown language with new elements is as simple as adding a new method to the class that converts the\nmarkdown text to the expected output in HTML. This is possible without dealing with complex and error prone regular expressions.\nIt is also possible to hook into the markdown structure and add elements or read meta information using the internal representation\nof the Markdown text as an abstract syntax tree (see [Extending the language](#extend)).\n\nCurrently the following markdown flavors are supported:\n\n- **Traditional Markdown** according to \u003chttp://daringfireball.net/projects/markdown/syntax\u003e ([try it!](http://markdown.cebe.cc/try?flavor=default)).\n- **Github flavored Markdown** according to \u003chttps://help.github.com/articles/github-flavored-markdown\u003e ([try it!](http://markdown.cebe.cc/try?flavor=gfm)).\n- **Markdown Extra** according to \u003chttp://michelf.ca/projects/php-markdown/extra/\u003e (currently not fully supported WIP see [#25][], [try it!](http://markdown.cebe.cc/try?flavor=extra))\n- Any mixed Markdown flavor you like because of its highly extensible structure (See documentation below).\n\nFuture plans are to support:\n\n- Smarty Pants \u003chttp://daringfireball.net/projects/smartypants/\u003e\n- ... (Feel free to [suggest](https://github.com/cebe/markdown/issues/new) further additions!)\n\n[PHP]: http://php.net/ \"PHP is a popular general-purpose scripting language that is especially suited to web development.\"\n[Markdown]: http://en.wikipedia.org/wiki/Markdown \"Markdown on Wikipedia\"\n[#25]: https://github.com/cebe/markdown/issues/25 \"issue #25\"\n[benchmark]: https://github.com/kzykhys/Markbench#readme \"kzykhys/Markbench on github\"\n\n### Who is using it?\n\n- It powers the [API-docs and the definitive guide](http://www.yiiframework.com/doc-2.0/) for the [Yii Framework][] [2.0](https://github.com/yiisoft/yii2).\n\n[Yii Framework]: http://www.yiiframework.com/ \"The Yii PHP Framework\"\n\n\nInstallation \u003ca name=\"installation\"\u003e\u003c/a\u003e\n------------\n\n[PHP 5.4 or higher](http://www.php.net/downloads.php) is required to use it.\nIt will also run on facebook's [hhvm](http://hhvm.com/).\n\nThe library uses PHPDoc annotations to determine the markdown elements that should be parsed.\nSo in case you are using PHP `opcache`, make sure \n[it does not strip comments](http://php.net/manual/en/opcache.configuration.php#ini.opcache.save-comments).\n\nInstallation is recommended to be done via [composer][] by running:\n\n\tcomposer require cebe/markdown \"~1.2.0\"\n\nAlternatively you can add the following to the `require` section in your `composer.json` manually:\n\n```json\n\"cebe/markdown\": \"~1.2.0\"\n```\n\nRun `composer update cebe/markdown` afterwards.\n\n[composer]: https://getcomposer.org/ \"The PHP package manager\"\n\n\u003e Note: If you have configured PHP with opcache you need to enable the\n\u003e [opcache.save_comments](http://php.net/manual/en/opcache.configuration.php#ini.opcache.save-comments) option because inline element parsing relies on PHPdoc annotations to find declared elements.\n\nUsage \u003ca name=\"usage\"\u003e\u003c/a\u003e\n-----\n\n### In your PHP project\n\nTo parse your markdown you need only two lines of code. The first one is to choose the markdown flavor as\none of the following:\n\n- Traditional Markdown: `$parser = new \\cebe\\markdown\\Markdown();`\n- Github Flavored Markdown: `$parser = new \\cebe\\markdown\\GithubMarkdown();`\n- Markdown Extra: `$parser = new \\cebe\\markdown\\MarkdownExtra();`\n\nThe next step is to call the `parse()`-method for parsing the text using the full markdown language\nor calling the `parseParagraph()`-method to parse only inline elements.\n\nHere are some examples:\n\n```php\n// traditional markdown and parse full text\n$parser = new \\cebe\\markdown\\Markdown();\necho $parser-\u003eparse($markdown);\n\n// use github markdown\n$parser = new \\cebe\\markdown\\GithubMarkdown();\necho $parser-\u003eparse($markdown);\n\n// use markdown extra\n$parser = new \\cebe\\markdown\\MarkdownExtra();\necho $parser-\u003eparse($markdown);\n\n// parse only inline elements (useful for one-line descriptions)\n$parser = new \\cebe\\markdown\\GithubMarkdown();\necho $parser-\u003eparseParagraph($markdown);\n```\n\nYou may optionally set one of the following options on the parser object:\n\nFor all Markdown Flavors:\n\n- `$parser-\u003ehtml5 = true` to enable HTML5 output instead of HTML4.\n- `$parser-\u003ekeepListStartNumber = true` to enable keeping the numbers of ordered lists as specified in the markdown.\n  The default behavior is to always start from 1 and increment by one regardless of the number in markdown.\n\nFor GithubMarkdown:\n\n- `$parser-\u003eenableNewlines = true` to convert all newlines to `\u003cbr/\u003e`-tags. By default only newlines with two preceding spaces are converted to `\u003cbr/\u003e`-tags. \n\nIt is recommended to use UTF-8 encoding for the input strings. Other encodings may work, but are currently untested.\n\n### The command line script\n\nYou can use it to render this readme:\n\n    bin/markdown README.md \u003e README.html\n\nUsing github flavored markdown:\n\n    bin/markdown --flavor=gfm README.md \u003e README.html\n\nor convert the original markdown description to html using the unix pipe:\n\n    curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown \u003e md.html\n\nHere is the full Help output you will see when running `bin/markdown --help`:\n\n    PHP Markdown to HTML converter\n    ------------------------------\n    \n    by Carsten Brandt \u003cmail@cebe.cc\u003e\n    \n    Usage:\n        bin/markdown [--flavor=\u003cflavor\u003e] [--full] [file.md]\n    \n        --flavor  specifies the markdown flavor to use. If omitted the original markdown by John Gruber [1] will be used.\n                  Available flavors:\n    \n                  gfm   - Github flavored markdown [2]\n                  extra - Markdown Extra [3]\n\n        --full    ouput a full HTML page with head and body. If not given, only the parsed markdown will be output.\n\n        --help    shows this usage information.\n\n        If no file is specified input will be read from STDIN.\n\n    Examples:\n\n        Render a file with original markdown:\n\n            bin/markdown README.md \u003e README.html\n\n        Render a file using gihtub flavored markdown:\n\n            bin/markdown --flavor=gfm README.md \u003e README.html\n\n        Convert the original markdown description to html using STDIN:\n\n            curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown \u003e md.html\n\n    \n    [1] http://daringfireball.net/projects/markdown/syntax\n    [2] https://help.github.com/articles/github-flavored-markdown\n    [3] http://michelf.ca/projects/php-markdown/extra/\n\n\nSecurity Considerations \u003ca name=\"security\"\u003e\u003c/a\u003e\n-----------------------\n\nBy design markdown [allows HTML to be included within the markdown text](https://daringfireball.net/projects/markdown/syntax#html).\nThis also means that it may contain Javascript and CSS styles. This allows to be very flexible\nfor creating output that is not limited by the markdown syntax, but it comes with\na security risk if you are parsing user input as markdown (see [XSS](https://en.wikipedia.org/wiki/Cross-site_scripting)).\n\nIn that case you should process the result of the markdown conversion with tools like \n[HTML Purifier](http://htmlpurifier.org/) that filter out all elements which are not allowed for users\nto be added.\n\nThe list of [allowed elements](http://htmlpurifier.org/live/configdoc/plain.html#HTML.AllowedElements) for\nmarkdown could be configured as:\n\n```php\n[\n    'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n    'hr',\n    'pre', 'code',\n    'blockquote',\n    'table', 'tr', 'td', 'th', 'thead', 'tbody',\n    'strong', 'em', 'b', 'i', 'u', 's', 'span',\n    'a', 'p', 'br', 'nobr',\n    'ul', 'ol', 'li',\n    'img',\n],\n```\n\nThe list of [allowed attributes](http://htmlpurifier.org/live/configdoc/plain.html#HTML.AllowedAttributes) would be:\n\n```php\n['th.align', 'td.align', 'ol.start', 'code.class']\n```\n\nThe above configuration is a general recommendation and may need to be adjusted dependent on your needs.\n\n\nExtensions\n----------\n\nHere are some extensions to this library:\n\n- [Bogardo/markdown-codepen](https://github.com/Bogardo/markdown-codepen) - shortcode to embed codepens from http://codepen.io/ in markdown.\n- [cebe/markdown-latex](https://github.com/cebe/markdown-latex) - Convert Markdown to LaTeX and PDF\n- [softark/creole](https://github.com/softark/creole) - A creole markup parser\n- [hyn/frontmatter](https://github.com/hyn/frontmatter) - Frontmatter Metadata Support (JSON, TOML, YAML)\n- ... [add yours!](https://github.com/cebe/markdown/edit/master/README.md#L186)\n\n\nExtending the language \u003ca name=\"extend\"\u003e\u003c/a\u003e\n----------------------\n\nMarkdown consists of two types of language elements, I'll call them block and inline elements simlar to what you have in\nHTML with `\u003cdiv\u003e` and `\u003cspan\u003e`. Block elements are normally spreads over several lines and are separated by blank lines.\nThe most basic block element is a paragraph (`\u003cp\u003e`).\nInline elements are elements that are added inside of block elements i.e. inside of text.\n\nThis markdown parser allows you to extend the markdown language by changing existing elements behavior and also adding\nnew block and inline elements. You do this by extending from the parser class and adding/overriding class methods and\nproperties. For the different element types there are different ways to extend them as you will see in the following sections.\n\n### Adding block elements\n\nThe markdown is parsed line by line to identify each non-empty line as one of the block element types.\nTo identify a line as the beginning of a block element it calls all protected class methods who's name begins with `identify`.\nAn identify function returns true if it has identified the block element it is responsible for or false if not.\nIn the following example we will implement support for [fenced code blocks][] which are part of the github flavored markdown.\n\n[fenced code blocks]: https://help.github.com/articles/github-flavored-markdown#fenced-code-blocks\n                      \"Fenced code block feature of github flavored markdown\"\n\n```php\n\u003c?php\n\nclass MyMarkdown extends \\cebe\\markdown\\Markdown\n{\n\tprotected function identifyFencedCode($line, $lines, $current)\n\t{\n\t\t// if a line starts with at least 3 backticks it is identified as a fenced code block\n\t\tif (strncmp($line, '```', 3) === 0) {\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\t// ...\n}\n```\n\nIn the above, `$line` is a string containing the content of the current line and is equal to `$lines[$current]`.\nYou may use `$lines` and `$current` to check other lines than the current line. In most cases you can ignore these parameters.\n\nParsing of a block element is done in two steps:\n\n1. **Consuming** all the lines belonging to it. In most cases this is iterating over the lines starting from the identified\n   line until a blank line occurs. This step is implemented by a method named `consume{blockName}()` where `{blockName}`\n   is the same name as used for the identify function above. The consume method also takes the lines array\n   and the number of the current line. It will return two arguments: an array representing the block element in the abstract syntax tree\n   of the markdown document and the line number to parse next. In the abstract syntax array the first element refers to the name of\n   the element, all other array elements can be freely defined by yourself.\n   In our example we will implement it like this:\n\n   ```php\n\tprotected function consumeFencedCode($lines, $current)\n\t{\n\t\t// create block array\n\t\t$block = [\n\t\t\t'fencedCode',\n\t\t\t'content' =\u003e [],\n\t\t];\n\t\t$line = rtrim($lines[$current]);\n\n\t\t// detect language and fence length (can be more than 3 backticks)\n\t\t$fence = substr($line, 0, $pos = strrpos($line, '`') + 1);\n\t\t$language = substr($line, $pos);\n\t\tif (!empty($language)) {\n\t\t\t$block['language'] = $language;\n\t\t}\n\n\t\t// consume all lines until ```\n\t\tfor($i = $current + 1, $count = count($lines); $i \u003c $count; $i++) {\n\t\t\tif (rtrim($line = $lines[$i]) !== $fence) {\n\t\t\t\t$block['content'][] = $line;\n\t\t\t} else {\n\t\t\t\t// stop consuming when code block is over\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn [$block, $i];\n\t}\n\t```\n\n2. **Rendering** the element. After all blocks have been consumed, they are being rendered using the\n   `render{elementName}()`-method where `elementName` refers to the name of the element in the abstract syntax tree:\n\n   ```php\n\tprotected function renderFencedCode($block)\n\t{\n\t\t$class = isset($block['language']) ? ' class=\"language-' . $block['language'] . '\"' : '';\n\t\treturn \"\u003cpre\u003e\u003ccode$class\u003e\" . htmlspecialchars(implode(\"\\n\", $block['content']) . \"\\n\", ENT_NOQUOTES, 'UTF-8') . '\u003c/code\u003e\u003c/pre\u003e';\n\t}\n   ```\n\n   You may also add code highlighting here. In general it would also be possible to render ouput in a different language than\n   HTML for example LaTeX.\n\n\n### Adding inline elements\n\nAdding inline elements is different from block elements as they are parsed using markers in the text.\nAn inline element is identified by a marker that marks the beginning of an inline element (e.g. `[` will mark a possible\nbeginning of a link or `` ` `` will mark inline code).\n\nParsing methods for inline elements are also protected and identified by the prefix `parse`. Additionally a `@marker` annotation\nin PHPDoc is needed to register the parse function for one or multiple markers.\nThe method will then be called when a marker is found in the text. As an argument it takes the text starting at the position of the marker.\nThe parser method will return an array containing the element of the abstract sytnax tree and an offset of text it has\nparsed from the input markdown. All text up to this offset will be removed from the markdown before the next marker will be searched.\n\nAs an example, we will add support for the [strikethrough][] feature of github flavored markdown:\n\n[strikethrough]: https://help.github.com/articles/github-flavored-markdown#strikethrough \"Strikethrough feature of github flavored markdown\"\n\n```php\n\u003c?php\n\nclass MyMarkdown extends \\cebe\\markdown\\Markdown\n{\n\t/**\n\t * @marker ~~\n\t */\n\tprotected function parseStrike($markdown)\n\t{\n\t\t// check whether the marker really represents a strikethrough (i.e. there is a closing ~~)\n\t\tif (preg_match('/^~~(.+?)~~/', $markdown, $matches)) {\n\t\t\treturn [\n\t\t\t    // return the parsed tag as an element of the abstract syntax tree and call `parseInline()` to allow\n\t\t\t    // other inline markdown elements inside this tag\n\t\t\t\t['strike', $this-\u003eparseInline($matches[1])],\n\t\t\t\t// return the offset of the parsed text\n\t\t\t\tstrlen($matches[0])\n\t\t\t];\n\t\t}\n\t\t// in case we did not find a closing ~~ we just return the marker and skip 2 characters\n\t\treturn [['text', '~~'], 2];\n\t}\n\n\t// rendering is the same as for block elements, we turn the abstract syntax array into a string.\n\tprotected function renderStrike($element)\n\t{\n\t\treturn '\u003cdel\u003e' . $this-\u003erenderAbsy($element[1]) . '\u003c/del\u003e';\n\t}\n}\n```\n\n### Composing your own Markdown flavor\n\nThis markdown library is composed of traits so it is very easy to create your own markdown flavor by adding and/or removing\nthe single feature traits.\n\nDesigning your Markdown flavor consists of four steps:\n\n1. Select a base class\n2. Select language feature traits\n3. Define escapeable characters\n4. Optionally add custom rendering behavior\n\n#### Select a base class\n\nIf you want to extend from a flavor and only add features you can use one of the existing classes\n(`Markdown`, `GithubMarkdown` or `MarkdownExtra`) as your flavors base class.\n\nIf you want to define a subset of the markdown language, i.e. remove some of the features, you have to\nextend your class from `Parser`.\n\n#### Select language feature traits\n\nThe following shows the trait selection for traditional Markdown.\n\n```php\nclass MyMarkdown extends Parser\n{\n\t// include block element parsing using traits\n\tuse block\\CodeTrait;\n\tuse block\\HeadlineTrait;\n\tuse block\\HtmlTrait {\n\t\tparseInlineHtml as private;\n\t}\n\tuse block\\ListTrait {\n\t\t// Check Ul List before headline\n\t\tidentifyUl as protected identifyBUl;\n\t\tconsumeUl as protected consumeBUl;\n\t}\n\tuse block\\QuoteTrait;\n\tuse block\\RuleTrait {\n\t\t// Check Hr before checking lists\n\t\tidentifyHr as protected identifyAHr;\n\t\tconsumeHr as protected consumeAHr;\n\t}\n\t// include inline element parsing using traits\n\tuse inline\\CodeTrait;\n\tuse inline\\EmphStrongTrait;\n\tuse inline\\LinkTrait;\n\n\t/**\n\t * @var boolean whether to format markup according to HTML5 spec.\n\t * Defaults to `false` which means that markup is formatted as HTML4.\n\t */\n\tpublic $html5 = false;\n\n\tprotected function prepare()\n\t{\n\t\t// reset references\n\t\t$this-\u003ereferences = [];\n\t}\n\n\t// ...\n}\n```\n\nIn general, just adding the trait with `use` is enough, however in some cases some fine tuning is desired\nto get most expected parsing results. Elements are detected in alphabetical order of their identification\nfunction. This means that if a line starting with `-` could be a list or a horizontal rule, the preference has to be set\nby renaming the identification function. This is what is done with renaming `identifyHr` to `identifyAHr`\nand `identifyBUl` to `identifyBUl`. The consume function always has to have the same name as the identification function\nso this has to be renamed too.\n\nThere is also a conflict for parsing of the `\u003c` character. This could either be a link/email enclosed in `\u003c` and `\u003e`\nor an inline HTML tag. In order to resolve this conflict when adding the `LinkTrait`, we need to hide the `parseInlineHtml`\nmethod of the `HtmlTrait`.\n\nIf you use any trait that uses the `$html5` property to adjust its output you also need to define this property.\n\nIf you use the link trait it may be useful to implement `prepare()` as shown above to reset references before\nparsing to ensure you get a reusable object.\n\n#### Define escapeable characters\n\nDepending on the language features you have chosen there is a different set of characters that can be escaped\nusing `\\`. The following is the set of escapeable characters for traditional markdown, you can copy it to your class\nas is.\n\n```php\n\t/**\n\t * @var array these are \"escapeable\" characters. When using one of these prefixed with a\n\t * backslash, the character will be outputted without the backslash and is not interpreted\n\t * as markdown.\n\t */\n\tprotected $escapeCharacters = [\n\t\t'\\\\', // backslash\n\t\t'`', // backtick\n\t\t'*', // asterisk\n\t\t'_', // underscore\n\t\t'{', '}', // curly braces\n\t\t'[', ']', // square brackets\n\t\t'(', ')', // parentheses\n\t\t'#', // hash mark\n\t\t'+', // plus sign\n\t\t'-', // minus sign (hyphen)\n\t\t'.', // dot\n\t\t'!', // exclamation mark\n\t\t'\u003c', '\u003e',\n\t];\n```\n\n#### Add custom rendering behavior\n\nOptionally you may also want to adjust rendering behavior by overriding some methods.\nYou may refer to the `consumeParagraph()` method of the `Markdown` and `GithubMarkdown` classes for some inspiration\nwhich define different rules for which elements are allowed to interrupt a paragraph.\n\n\nAcknowledgements \u003ca name=\"ack\"\u003e\u003c/a\u003e\n----------------\n\nI'd like to thank [@erusev][] for creating [Parsedown][] which heavily influenced this work and provided\nthe idea of the line based parsing approach.\n\n[@erusev]: https://github.com/erusev \"Emanuil Rusev\"\n[Parsedown]: http://parsedown.org/ \"The Parsedown PHP Markdown parser\"\n\nFAQ \u003ca name=\"faq\"\u003e\u003c/a\u003e\n---\n\n### Why another markdown parser?\n\nWhile reviewing PHP markdown parsers for choosing one to use bundled with the [Yii framework 2.0][]\nI found that most of the implementations use regex to replace patterns instead\nof doing real parsing. This way extending them with new language elements is quite hard\nas you have to come up with a complex regex, that matches your addition but does not mess\nwith other elements. Such additions are very common as you see on github which supports referencing\nissues, users and commits in the comments.\nA [real parser][] should use context aware methods that walk trough the text and\nparse the tokens as they find them. The only implentation that I have found that uses\nthis approach is [Parsedown][] which also shows that this implementation is [much faster][benchmark]\nthan the regex way. Parsedown however is an implementation that focuses on speed and implements\nits own flavor (mainly github flavored markdown) in one class and at the time of this writing was\nnot easily extensible.\n\nGiven the situation above I decided to start my own implementation using the parsing approach\nfrom Parsedown and making it extensible creating a class for each markdown flavor that extend each\nother in the way that also the markdown languages extend each other.\nThis allows you to choose between markdown language flavors and also provides a way to compose your\nown flavor picking the best things from all.\nI chose this approach as it is easier to implement and also more intuitive approach compared\nto using callbacks to inject functionallity into the parser.\n\n[real parser]: http://en.wikipedia.org/wiki/Parsing#Types_of_parser\n\n[Parsedown]: http://parsedown.org/ \"The Parsedown PHP Markdown parser\"\n\n[Yii framework 2.0]: https://github.com/yiisoft/yii2\n\n### Where do I report bugs or rendering issues?\n\nJust [open an issue][] on github, post your markdown code and describe the problem. You may also attach screenshots of the rendered HTML result to describe your problem.\n\n[open an issue]: https://github.com/cebe/markdown/issues/new\n\n### How can I contribute to this library?\n\nCheck the [CONTRIBUTING.md](CONTRIBUTING.md) file for more info.\n\n\n### Am I free to use this?\n\nThis library is open source and licensed under the [MIT License][]. This means that you can do whatever you want\nwith it as long as you mention my name and include the [license file][license]. Check the [license][] for details.\n\n[MIT License]: http://opensource.org/licenses/MIT\n\n[license]: https://github.com/cebe/markdown/blob/master/LICENSE\n\nContact\n-------\n\nFeel free to contact me using [email](mailto:mail@cebe.cc) or [twitter](https://twitter.com/cebe_cc).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcebe%2Fmarkdown","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcebe%2Fmarkdown","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcebe%2Fmarkdown/lists"}