Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
CommonMark
Markdown done right
Colin O’Dell
@colinodell
COLIN O’DELL
Creator & Maintainer of league/commonmark
Lead Web Developer at Unleashed Technologies
Author of PHP 7 Migrat...
TOPICS
Origins of Markdown
CommonMark Spec
league/commonmark Overview
Customizing league/commonmark
ORIGINS OF MARKDOWN
Created in March 2004 by John Gruber
Informal plain-text formatting language
Converts readable text...
HISTORY OF MARKDOWN
Hello Nomad PHP!
----------------
Markdown is **awesome**!
1. Foo
2. Bar
3. Baz
Wikipedia entry:
<http...
WHY IS IT SUCCESSFUL?
1. Syntax is visually-similar to the resulting
markup
2. Non-strict, forgiving parsing
3. Easily ada...
67+ DIFFERENT FLAVORS
Source: https://github.com/markdown/markdown.github.com/wiki/Implementations
Actuarius
Blackfriday
B...
https://xkcd.com/927/
COMMONMARK IS…
A strongly defined, highly compatible specification of Markdown.
Written by John MacFarlane
(in collaborati...
WHY IS IT NEEDED?
*I love Markdown*
<p><em>I love Markdown</em></p>
WHY IS IT NEEDED?
*I *love* Markdown*
WHY IS IT NEEDED? Source: http://johnmacfarlane.net/babelmark2/
30%
WHY IS IT NEEDED?
*I *love* Markdown*
<p><em>I <em>love</em> Markdown</em></p>
*I *love* Markdown*
<p><em>I </em>love<...
WHY IS IT NEEDED?
1. > Hello
World!
------
Source: http://johnmacfarlane.net/babelmark2/
WHY IS IT NEEDED?
1. > Hello
World!
------
Source: http://johnmacfarlane.net/babelmark2/
WHY IS IT NEEDED?
1. > Hello
World!
------
Source: http://johnmacfarlane.net/babelmark2/
WHY IS IT NEEDED?
1. > Hello
World!
------
Source: http://johnmacfarlane.net/babelmark2/
WHY IS IT NEEDED?
1. > Hello
World!
------
Source: http://johnmacfarlane.net/babelmark2/
LEAGUE/COMMONMARK
A well-written, super-configurable
Markdown parser for PHP based on the
CommonMark spec.
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
ADDING LEAGUE/COMMONMARK
$ composer require league/commonmark:^0.14
<?php
$converter = new CommonMarkConverter();
echo $co...
INTEGRATIONS
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
CONVERSION PROCESS
<https://nomadphp.com>
<a href="https://nomadphp.com">
https://nomadphp.com
</a>
CONVERSION PROCESS
<https://nomadphp.com>
Markdow
n
Parse
<document>
<paragraph>
<link destination="https://nomadphp.com">
<text>https://nomadphp.com</text>
</link>
</paragraph>
</...
CONVERSION PROCESS
<a href="https://nomadphp.com">
https://nomadphp.com
</a>
Markdow
n
AST HTMLRenderParse
CONVERSION PROCESS
Markdow
n
AST HTMLRenderParse
Add your own custom parser, processor, or renderer
EXAMPLE 1: CUSTOM PARSER
<https://nomadphp.com>
<a href="https://nomadphp.com">
https://nomadphp.com
</a>
<@colinodell>
<a...
class TwitterUsernameAutolinkParser extends AbstractInlineParser {
public function getCharacters() {
return ['<'];
}
publi...
CURSOR
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLine()
getPos...
CURSOR::ADVANCE()
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLi...
CURSOR::ADVANCEBY(INT)
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
...
CURSOR::PEEK(INT)
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLi...
CURSOR
Learning CommonMark with <@colinodell>!
public function getCharacters()
{
return ['<'];
}
CURSOR
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLine()
getPos...
CURSOR
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLine()
getPos...
CUSTOMIZING LEAGUE/COMMONMARK
class TwitterUsernameAutolinkParser extends AbstractInlineParser {
public function getCharac...
$environment = Environment::createCommonMarkEnvironment();
$environment->addInlineParser(
new TwitterHandleParser()
);
$co...
EXAMPLE 2: CUSTOM AST PROCESSOR
<document>
<paragraph>
<link destination="https://nomadphp.com">
<text>https://nomadphp.co...
class ShortenLinkProcessor implements DocumentProcessorInterface {
public function processDocument(Document $document) {
$...
$environment = Environment::createCommonMarkEnvironment();
$environment->addDocumentProcessor(
new ShortenLinkProcessor()
...
EXAMPLE 3: CUSTOM RENDERER
<document>
<paragraph>
<text>Hello World!</text>
</paragraph>
<thematic_break />
</document>
<p...
EXAMPLE 3: CUSTOM RENDERER
class ImageHorizontalRuleRenderer implements BlockRendererInterface {
public function render(.....
$environment = Environment::createCommonMarkEnvironment();
$environment->addBlockRenderer(
LeagueCommonMarkBlockElementThe...
BUNDLING INTO AN EXTENSION
class MyCustomExtension extends Extension {
public function getInlineParsers() {
return [new Tw...
BUNDLING INTO AN EXTENSION
$environment = Environment::createCommonMarkEnvironment();
$environment->addExtension(new MyCus...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
WELL-TESTED
 94% code coverage
 Functional tests
 All 616 spec examples
 Library of regression tests
 Unit tests
 Cu...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
PERFORMANCE
0 20 40 60 80 100
Parsedown
PHP Markdown Extra
Time (ms)
league/commonmark is ~35-40ms
slower
PHP 5.6 PHP 7.0
...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
STABILITY
 Current version: 0.15.0
 Conforms to CommonMark spec 0.26
 1.0.0 will be released once CommonMark spec is 1....
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent perform...
Installation & Documentation:
http://github.com/thephpleague/commonmark
Learn More About CommonMark:
http://commonmark.org...
CommonMark: Markdown done right - Nomad PHP September 2016
CommonMark: Markdown done right - Nomad PHP September 2016
CommonMark: Markdown done right - Nomad PHP September 2016
CommonMark: Markdown done right - Nomad PHP September 2016
Nächste SlideShare
Wird geladen in …5
×

CommonMark: Markdown done right - Nomad PHP September 2016

607 Aufrufe

Veröffentlicht am

Markdown is one of the most popular markup languages on the Web. Unfortunately, with no standard specification, every implementation works differently, producing varying results across different platforms. The CommonMark specification fixes this by providing an unambiguous syntax specification and a comprehensive suite of tests. Attendees will learn about this standard and how to integrate the league/commonmark parser into their applications. We will also cover how to add new syntax and other features to the parser to fit your custom needs.

Veröffentlicht in: Technologie
  • Als Erste(r) kommentieren

CommonMark: Markdown done right - Nomad PHP September 2016

  1. 1. CommonMark Markdown done right Colin O’Dell @colinodell
  2. 2. COLIN O’DELL Creator & Maintainer of league/commonmark Lead Web Developer at Unleashed Technologies Author of PHP 7 Migration Guide e-book @colinodell
  3. 3. TOPICS Origins of Markdown CommonMark Spec league/commonmark Overview Customizing league/commonmark
  4. 4. ORIGINS OF MARKDOWN Created in March 2004 by John Gruber Informal plain-text formatting language Converts readable text to valid (X)HTML Primary goal - readability
  5. 5. HISTORY OF MARKDOWN Hello Nomad PHP! ---------------- Markdown is **awesome**! 1. Foo 2. Bar 3. Baz Wikipedia entry: <https://en.wikipedia.org/wiki/Markdown>
  6. 6. WHY IS IT SUCCESSFUL? 1. Syntax is visually-similar to the resulting markup 2. Non-strict, forgiving parsing 3. Easily adaptable for different uses
  7. 7. 67+ DIFFERENT FLAVORS Source: https://github.com/markdown/markdown.github.com/wiki/Implementations Actuarius Blackfriday BlueCloth BlueFeather cebe/markdown CocoaMarkdown Discount ffi-sundown GHMarkdownParser Goskirt Hoedown Hoep Knockoff kramdown Laika libpandoc Lowdown lua-discount Lunamark markdown markdown-clj markdown-js markdown-oo-php markdown.bash markdown.lua markdown.pl markdown4j MarkdownDeep MarkdownJ MarkdownPapers MarkdownSharp marked Maruku md2html.awk Misaka Mistune MMMarkdown MoonShine MultiMarkdown node-discount node-markdown node-multimarkdown OMD Pandoc Parsedown Parsedown Extra peg-markdown peg-multimarkdown & fork pegdown PHP Markdown PHP Markdown Extra PHP-Sundown Python-Discount python-hoedown Python-Markdown Python-Markdown2 RDiscount Redcarpet RoboSkirt Showdown Sundown Sundown HS Sundown.net text-markdown texts.js Txtmark upskirt.go
  8. 8. https://xkcd.com/927/
  9. 9. COMMONMARK IS… A strongly defined, highly compatible specification of Markdown. Written by John MacFarlane (in collaboration with people from Github, StackOverflow, Reddit, and others) Spec includes:  Strict rules (precedence, parsing order, handling edge cases)  Specific definitions (ex: “whitespace”, “punctuation”)  616 examples
  10. 10. WHY IS IT NEEDED? *I love Markdown* <p><em>I love Markdown</em></p>
  11. 11. WHY IS IT NEEDED? *I *love* Markdown*
  12. 12. WHY IS IT NEEDED? Source: http://johnmacfarlane.net/babelmark2/
  13. 13. 30% WHY IS IT NEEDED? *I *love* Markdown* <p><em>I <em>love</em> Markdown</em></p> *I *love* Markdown* <p><em>I </em>love<em> Markdown</em></p> *I *love* Markdown* <p><em>I *love</em> Markdown*</p> 15% 33% Source: http://johnmacfarlane.net/babelmark2/
  14. 14. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  15. 15. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  16. 16. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  17. 17. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  18. 18. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  19. 19. LEAGUE/COMMONMARK A well-written, super-configurable Markdown parser for PHP based on the CommonMark spec.
  20. 20. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  21. 21. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  22. 22. ADDING LEAGUE/COMMONMARK $ composer require league/commonmark:^0.14 <?php $converter = new CommonMarkConverter(); echo $converter->convertToHtml('Hello **Nomad PHP!**');
  23. 23. INTEGRATIONS
  24. 24. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  25. 25. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  26. 26. CONVERSION PROCESS <https://nomadphp.com> <a href="https://nomadphp.com"> https://nomadphp.com </a>
  27. 27. CONVERSION PROCESS <https://nomadphp.com> Markdow n Parse
  28. 28. <document> <paragraph> <link destination="https://nomadphp.com"> <text>https://nomadphp.com</text> </link> </paragraph> </document> CONVERSION PROCESS Markdow n AST RenderParse
  29. 29. CONVERSION PROCESS <a href="https://nomadphp.com"> https://nomadphp.com </a> Markdow n AST HTMLRenderParse
  30. 30. CONVERSION PROCESS Markdow n AST HTMLRenderParse Add your own custom parser, processor, or renderer
  31. 31. EXAMPLE 1: CUSTOM PARSER <https://nomadphp.com> <a href="https://nomadphp.com"> https://nomadphp.com </a> <@colinodell> <a href="https://twitter.com/colinodell"> @colinodell </a>
  32. 32. class TwitterUsernameAutolinkParser extends AbstractInlineParser { public function getCharacters() { return ['<']; } public function parse(InlineParserContext $inlineContext) { $cursor = $inlineContext->getCursor(); } }
  33. 33. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  34. 34. CURSOR::ADVANCE() Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  35. 35. CURSOR::ADVANCEBY(INT) Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  36. 36. CURSOR::PEEK(INT) Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  37. 37. CURSOR Learning CommonMark with <@colinodell>! public function getCharacters() { return ['<']; }
  38. 38. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  39. 39. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count) /^<@[A-Za-z0-9_]+>/
  40. 40. CUSTOMIZING LEAGUE/COMMONMARK class TwitterUsernameAutolinkParser extends AbstractInlineParser { public function getCharacters() { return ['<']; } public function parse(InlineParserContext $inlineContext) { $cursor = $inlineContext->getCursor(); if ($match = $cursor->match('/^<@[A-Za-z0-9_]+>/')) { // Remove the starting '<@' and ending '>' that were matched $username = substr($match, 2, -1); $profileUrl = 'https://twitter.com/' . $username; $link = new Link($profileUrl, '@'.$username); $inlineContext->getContainer()->appendChild($link); return true; } return false; } }
  41. 41. $environment = Environment::createCommonMarkEnvironment(); $environment->addInlineParser( new TwitterHandleParser() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml( "Follow <@colinodell> on Twitter!" );
  42. 42. EXAMPLE 2: CUSTOM AST PROCESSOR <document> <paragraph> <link destination="https://nomadphp.com"> <text>https://nomadphp.com</text> </link> </paragraph> </document> <document> <paragraph> <link destination="https://bit.ly/foo"> <text>https://nomadphp.com</text> </link> </paragraph> </document>
  43. 43. class ShortenLinkProcessor implements DocumentProcessorInterface { public function processDocument(Document $document) { $walker = $document->walker(); while ($event = $walker->next()) { if ($event->isEntering() && $event->getNode() instanceof Link) { /** @var Link $linkNode */ $linkNode = $event->getNode(); $originalUrl = $linkNode->getUrl(); $shortUrl = $this->bitly->shorten($originalUrl); $linkNode->setUrl($shortUrl); } } } }
  44. 44. $environment = Environment::createCommonMarkEnvironment(); $environment->addDocumentProcessor( new ShortenLinkProcessor() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml( "Meetings: <https://nomadphp.com/upcoming/>" ); EXAMPLE 2: CUSTOM AST PROCESSOR
  45. 45. EXAMPLE 3: CUSTOM RENDERER <document> <paragraph> <text>Hello World!</text> </paragraph> <thematic_break /> </document> <p>Hello World!</p> <hr /> <p>Hello World!</p> <img src="hr.png" />
  46. 46. EXAMPLE 3: CUSTOM RENDERER class ImageHorizontalRuleRenderer implements BlockRendererInterface { public function render(...) { return new HtmlElement('img', ['src' => 'hr.png']); } }
  47. 47. $environment = Environment::createCommonMarkEnvironment(); $environment->addBlockRenderer( LeagueCommonMarkBlockElementThematicBreak::class, new ImageHorizontalRuleRenderer() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml("Hello World!nn-----"); EXAMPLE 3: CUSTOM RENDERER
  48. 48. BUNDLING INTO AN EXTENSION class MyCustomExtension extends Extension { public function getInlineParsers() { return [new TwitterUsernameAutolinkParser()]; } public function getDocumentProcessors() { return [new ShortenLinkProcessor()]; } public function getBlockRenderers() { return [new ImageHorizontalRuleRenderer()]; } }
  49. 49. BUNDLING INTO AN EXTENSION $environment = Environment::createCommonMarkEnvironment(); $environment->addExtension(new MyCustomExtension()); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml("...");
  50. 50. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  51. 51. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  52. 52. WELL-TESTED  94% code coverage  Functional tests  All 616 spec examples  Library of regression tests  Unit tests  Cursor  Environment  Utility classes
  53. 53. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  54. 54. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  55. 55. PERFORMANCE 0 20 40 60 80 100 Parsedown PHP Markdown Extra Time (ms) league/commonmark is ~35-40ms slower PHP 5.6 PHP 7.0 Tips: • Use PHP 7 (50-80% boost) • Choose library based on your needs • Cache rendered HTML (100% boost) • Optimize custom functionality
  56. 56. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  57. 57. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  58. 58. STABILITY  Current version: 0.15.0  Conforms to CommonMark spec 0.26  1.0.0 will be released once CommonMark spec is 1.0  No major stability issues  Backwards Compatibility Promise:  No BC breaks to CommonMarkConverter class in 0.x  Other BC breaks will be documented
  59. 59. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  60. 60. Installation & Documentation: http://github.com/thephpleague/commonmark Learn More About CommonMark: http://commonmark.org Slides / Feedback: https://joind.in/talk/22293 @colinodell

×