Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

CommonMark: Markdown Done Right

593 views

Published on

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 custom features.

Published in: Software
  • Be the first to comment

  • Be the first to like this

CommonMark: Markdown Done Right

  1. 1. CommonMark Markdown done right Colin O’Dell @colinodell
  2. 2. COLIN O’DELL Creator & Maintainer of league/commonmark LeadWeb Developer at UnleashedTechnologies Author of PHP 7 Migration Guide e-book @colinodell www.colinodell.com
  3. 3. LEAGUE/COMMONMARK A well-written, super-configurable Markdown parser for PHP based on the CommonMark spec.
  4. 4. COMMONMARK IS… A strongly defined, highly compatible specification of Markdown. Written by people from Github, StackOverflow, Reddit, and others. Spec includes:  Strict rules (precedence, parsing order, handling edge cases)  Specific definitions (ex:“whitespace”,“punctuation”)  616 examples
  5. 5. WHY IS IT NEEDED? *I love Markdown* <p><em>I love Markdown</em></p>
  6. 6. WHY IS IT NEEDED? *I *love* Markdown*
  7. 7. WHY IS IT NEEDED? Source: http://johnmacfarlane.net/babelmark2/
  8. 8. 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/
  9. 9. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  10. 10. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  11. 11. ADDING LEAGUE/COMMONMARK $ composer require league/commonmark:^0.13 <?php $converter = new CommonMarkConverter(); echo $converter->convertToHtml('Hello **php[tek]!**');
  12. 12. INTEGRATIONS
  13. 13. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  14. 14. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  15. 15. CONVERSION PROCESS <https://tek.phparch.com> <a href="https://tek.phparch.com"> https://tek.phparch.com </a>
  16. 16. CONVERSION PROCESS <https://tek.phparch.com> Markdown Parse
  17. 17. <document> <paragraph> <link destination="https://tek.phparch.com"> <text>https://tek.phparch.com</text> </link> </paragraph> </document> CONVERSION PROCESS Markdown AST RenderParse
  18. 18. CONVERSION PROCESS <a href="https://tek.phparch.com"> https://tek.phparch.com </a> Markdown AST HTMLRenderParse
  19. 19. CONVERSION PROCESS Markdown AST HTMLRenderParse Add your own custom parser, processor, or renderer
  20. 20. EXAMPLE 1: CUSTOM PARSER <https://tek.phparch.com> <a href="https://tek.phparch.com"> https://tek.phparch.com </a> <@colinodell> <a href="https://twitter.com/colinodell"> @colinodell </a>
  21. 21. class TwitterUsernameAutolinkParser extends AbstractInlineParser { public function getCharacters() { return ['<']; } public function parse(InlineParserContext $inlineContext) { $cursor = $inlineContext->getCursor(); } }
  22. 22. CURSOR Learning CommonMark with <@colinodell>! public function getCharacters() { return ['<']; }
  23. 23. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter() getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  24. 24. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter() getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count)
  25. 25. 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_]+>/
  26. 26. 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; } }
  27. 27. $environment = Environment::createCommonMarkEnvironment(); $environment->addInlineParser( new TwitterHandleParser() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml( "Follow <@colinodell> on Twitter!" );
  28. 28. EXAMPLE 2: CUSTOM AST PROCESSOR <document> <paragraph> <link destination="https://tek.phparch.com"> <text>https://tek.phparch.com</text> </link> </paragraph> </document> <document> <paragraph> <link destination="https://bit.ly/foo"> <text>https://tek.phparch.com</text> </link> </paragraph> </document>
  29. 29. 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); } } } }
  30. 30. $environment = Environment::createCommonMarkEnvironment(); $environment->addDocumentProcessor( new ShortenLinkProcessor() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml( "Schedule: <https://tek.phparch.com/schedule>" ); EXAMPLE 2: CUSTOM AST PROCESSOR
  31. 31. 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" />
  32. 32. EXAMPLE 3: CUSTOM RENDERER class ImageHorizontalRuleRenderer implements BlockRendererInterface { public function render(...) { return new HtmlElement('img', ['src' => 'hr.png']); } }
  33. 33. $environment = Environment::createCommonMarkEnvironment(); $environment->addBlockRenderer( LeagueCommonMarkBlockElementThematicBreak::class, new ImageHorizontalRuleRenderer() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml("Hello World!nn-----"); EXAMPLE 3: CUSTOM RENDERER
  34. 34. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  35. 35. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  36. 36. WELL-TESTED  94% code coverage  Functional tests  All 616 spec examples  Library of regression tests  Unit tests  Cursor  Environment  Utility classes
  37. 37. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  38. 38. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  39. 39. PERFORMANCE 0 20 40 60 80 100 Parsedown cebe/markdown PHP Markdown Extra league/commonmark Time (ms) league/commonmark is ~35-40ms slower PHP 5.6 PHP 7.0 Tips: • Choose library based on your needs • Cache rendered HTML (100% boost) • Use PHP 7 (50-80% boost) • Optimize custom functionality
  40. 40. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  41. 41. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  42. 42. STABILITY  Current version: 0.13.3  Conforms to CommonMark spec 0.25  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
  43. 43. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable
  44. 44. Installation & Documentation: http://github.com/thephpleague/commonmark Learn More About CommonMark: http://commonmark.org Slides / Feedback: https://joind.in/talk/96dc9 @colinodell

×