SlideShare a Scribd company logo
1 of 61
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 Migration Guide e-book
@colinodel
l
LEAGUE/COMMONMARK
A well-written, super-configurable
Markdown parser for PHP based on the
CommonMark spec.
@colinodel
l
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
@colinodel
l
HISTORY OF MARKDOWN
Hello ZendCon!
--------------
Markdown is **awesome**!
1. Foo
2. Bar
3. Baz
Wikipedia entry:
<https://en.wikipedia.org/wiki/Markdown> @colinodel
l
WHY IS IT SUCCESSFUL?
1. Syntax is visually-similar to the resulting
markup
2. Non-strict, forgiving parsing
3. Easily adaptable for different uses
@colinodel
l
68+ DIFFERENT FLAVORS
Source: https://github.com/markdown/markdown.github.com/wiki/Implementations
Actuarius
Blackfriday
BlueCloth
BlueFeather
cebe/markdown
CocoaMarkdown
CommonMark
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
@colinodel
l
https://xkcd.com/927/
@colinodel
l
WHY IS IT NEEDED?
*I love Markdown*
<p><em>I love Markdown</em></p>
@colinodel
l
WHY IS IT NEEDED?
*I *love* Markdown*
@colinodel
l
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<em> Markdown</em></p>
*I *love* Markdown*
<p><em>I *love</em> Markdown*</p>
15%
33%
Source: http://johnmacfarlane.net/babelmark2/
@colinodel
l
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/
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”)
 624 examples
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
ADDING LEAGUE/COMMONMARK
$ composer require league/commonmark:^0.15
<?php
$converter = new CommonMarkConverter();
echo $converter->convertToHtml('Hello **ZendCon!**');
@colinodel
l
INTEGRATIONS
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
CONVERSION PROCESS
<http://www.zendcon.com>
<a href="http://www.zendcon.com">
http://www.zendcon.com
</a>
@colinodel
l
CONVERSION PROCESS
<http://www.zendcon.com>
Markdow
n
Parse
@colinodel
l
<document>
<paragraph>
<link destination="http://www.zendcon.com">
<text>http://www.zendcon.com</text>
</link>
</paragraph>
</document>
CONVERSION PROCESS
Markdow
n
AST RenderParse
@colinodel
l
CONVERSION PROCESS
<a href="http://www.zendcon.com">
http://www.zendcon.com
</a>
Markdow
n
AST HTMLRenderParse
@colinodel
l
CONVERSION PROCESS
Markdow
n
AST HTMLRenderParse
Add your own custom parser, processor, or renderer
@colinodel
l
EXAMPLE 1: CUSTOM PARSER
<http://www.zendcon.com>
<a href="http://www.zendcon.com">
http://www.zendcon.com
</a>
<@colinodell>
<a href="https://twitter.com/colinodell">
@colinodell
</a>
@colinodel
l
class TwitterUsernameAutolinkParser extends AbstractInlineParser {
public function getCharacters() {
return ['<'];
}
public function parse(InlineParserContext $inlineContext) {
// TODO
}
}
@colinodel
l
CURSOR
Learning CommonMark with <@colinodell>!
public function getCharacters()
{
return ['<'];
}
@colinodel
l
class TwitterUsernameAutolinkParser extends AbstractInlineParser {
public function getCharacters() {
return ['<'];
}
public function parse(InlineParserContext $inlineContext) {
$cursor = $inlineContext->getCursor();
}
}
@colinodel
l
CURSOR
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLine()
getPosition()
advance()
advanceBy($count)
advanceBySpaceOrTab()
advanceWhileMatches($char
)
advanceToFirstNonSpace()
isIndented()
isAtEnd()
match($regex)
peek($count)
@colinodel
l
CURSOR
Learning CommonMark with <@colinodell>!
getCharacter()
getFirstNonSpaceCharacter(
)
getRemainder()
getLine()
getPosition()
advance()
advanceBy($count)
advanceBySpaceOrTab()
advanceWhileMatches($char
)
advanceToFirstNonSpace()
isIndented()
isAtEnd()
match($regex)
peek($count)
@colinodel
l
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_]+>/
@colinodel
l
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;
}
}
@colinodel
l
$environment = Environment::createCommonMarkEnvironment();
$environment->addInlineParser(
new TwitterHandleParser()
);
$converter = new CommonMarkConverter($environment);
$html = $converter->convertToHtml(
"Follow <@colinodell> on Twitter!"
);
@colinodel
l
EXAMPLE 2: CUSTOM AST PROCESSOR
<document>
<paragraph>
<link destination="http://www.zendcon.com">
<text>http://www.zendcon.com</text>
</link>
</paragraph>
</document>
<document>
<paragraph>
<link destination="https://bit.ly/foo">
<text>http://www.zendcon.com</text>
</link>
</paragraph>
</document>
@colinodel
l
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);
}
}
}
}
@colinodel
l
$environment = Environment::createCommonMarkEnvironment();
$environment->addDocumentProcessor(
new ShortenLinkProcessor()
);
$converter = new CommonMarkConverter($environment);
$html = $converter->convertToHtml(
"Schedule: <http://www.zendcon.com/schedule>"
);
EXAMPLE 2: CUSTOM AST PROCESSOR
@colinodel
l
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" />
@colinodel
l
EXAMPLE 3: CUSTOM RENDERER
class ImageHorizontalRuleRenderer implements BlockRendererInterface {
public function render(...) {
return new HtmlElement('img', ['src' => 'hr.png']);
}
}
@colinodel
l
$environment = Environment::createCommonMarkEnvironment();
$environment->addBlockRenderer(
LeagueCommonMarkBlockElementThematicBreak::class,
new ImageHorizontalRuleRenderer()
);
$converter = new CommonMarkConverter($environment);
$html = $converter->convertToHtml("Hello World!nn-----");
EXAMPLE 3: CUSTOM RENDERER
@colinodel
l
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()];
}
}
@colinodel
l
BUNDLING INTO AN EXTENSION
$environment = Environment::createCommonMarkEnvironment();
$environment->addExtension(new MyCustomExtension());
$converter = new CommonMarkConverter($environment);
$html = $converter->convertToHtml("...");
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
WELL-TESTED
 94% code coverage
 Functional tests
 All 624 spec examples
 Library of regression tests
 Unit tests
 Cursor
 Environment
 Utility classes
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
PERFORMANCE
0 20 40 60 80
Parsedown
cebe/markdown gfm
PHP Markdown Extra
league/commonmark
Time (ms)
league/commonmark is ~22-24ms slower
PHP 5.6 PHP 7.1
Tips:
• Choose library based on your
needs
• Cache rendered HTML (100%
boost)
• Use PHP 7 (50% boost)
• Optimize custom functionality
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
STABILITY
 Current version: 0.15.6
 Conforms to CommonMark spec 0.28
 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 are documented (see UPGRADING.md)
@colinodel
l
FEATURES
 100% compliance with the CommonMark spec
 Easy to implement
 Easy to customize
 Well-tested
 Decent performance
 (Relatively) stable
@colinodel
l
Installation & Documentation:
http://github.com/thephpleague/commonmark
Learn More About CommonMark:
http://commonmark.org
Slides / Feedback:
https://joind.in/talk/8da74
@colinodell

More Related Content

What's hot

Seaside - The Revenge of Smalltalk
Seaside - The Revenge of SmalltalkSeaside - The Revenge of Smalltalk
Seaside - The Revenge of SmalltalkLukas Renggli
 
Lecture3 php by okello erick
Lecture3 php by okello erickLecture3 php by okello erick
Lecture3 php by okello erickokelloerick
 
Oracle Inter-Session Communication
Oracle Inter-Session CommunicationOracle Inter-Session Communication
Oracle Inter-Session CommunicationOren Nakdimon
 
How to upgrade your application with no downtime (using edition-based redefin...
How to upgrade your application with no downtime (using edition-based redefin...How to upgrade your application with no downtime (using edition-based redefin...
How to upgrade your application with no downtime (using edition-based redefin...Oren Nakdimon
 
Indexes and Indexing in Oracle 12c
Indexes and Indexing in Oracle 12cIndexes and Indexing in Oracle 12c
Indexes and Indexing in Oracle 12cOren Nakdimon
 
Drupal users group_symfony2
Drupal users group_symfony2Drupal users group_symfony2
Drupal users group_symfony2Brian Zitzow
 
Write Less (code) With More (Oracle Database 12c New Features)
Write Less (code) With More (Oracle Database 12c New Features)Write Less (code) With More (Oracle Database 12c New Features)
Write Less (code) With More (Oracle Database 12c New Features)Oren Nakdimon
 
XML-Free Programming
XML-Free ProgrammingXML-Free Programming
XML-Free ProgrammingStephen Chin
 

What's hot (11)

Seaside - The Revenge of Smalltalk
Seaside - The Revenge of SmalltalkSeaside - The Revenge of Smalltalk
Seaside - The Revenge of Smalltalk
 
Lecture3 php by okello erick
Lecture3 php by okello erickLecture3 php by okello erick
Lecture3 php by okello erick
 
Oracle Inter-Session Communication
Oracle Inter-Session CommunicationOracle Inter-Session Communication
Oracle Inter-Session Communication
 
How to upgrade your application with no downtime (using edition-based redefin...
How to upgrade your application with no downtime (using edition-based redefin...How to upgrade your application with no downtime (using edition-based redefin...
How to upgrade your application with no downtime (using edition-based redefin...
 
topic_perlcgi
topic_perlcgitopic_perlcgi
topic_perlcgi
 
Indexes and Indexing in Oracle 12c
Indexes and Indexing in Oracle 12cIndexes and Indexing in Oracle 12c
Indexes and Indexing in Oracle 12c
 
Bpel4 Ws 1.1 To Ws Bpel 2.0
Bpel4 Ws 1.1 To Ws Bpel 2.0Bpel4 Ws 1.1 To Ws Bpel 2.0
Bpel4 Ws 1.1 To Ws Bpel 2.0
 
Drupal users group_symfony2
Drupal users group_symfony2Drupal users group_symfony2
Drupal users group_symfony2
 
R3 tosrm attach
R3 tosrm attachR3 tosrm attach
R3 tosrm attach
 
Write Less (code) With More (Oracle Database 12c New Features)
Write Less (code) With More (Oracle Database 12c New Features)Write Less (code) With More (Oracle Database 12c New Features)
Write Less (code) With More (Oracle Database 12c New Features)
 
XML-Free Programming
XML-Free ProgrammingXML-Free Programming
XML-Free Programming
 

Similar to CommonMark: Markdown Done Right - ZendCon 2017

CommonMark: Markdown Done Right
CommonMark: Markdown Done RightCommonMark: Markdown Done Right
CommonMark: Markdown Done RightColin O'Dell
 
ngManila - Codename: Fireball - Hello World in Angular
ngManila - Codename: Fireball - Hello World in AngularngManila - Codename: Fireball - Hello World in Angular
ngManila - Codename: Fireball - Hello World in Angularngmanila
 
Introduction to league/commonmark
Introduction to league/commonmarkIntroduction to league/commonmark
Introduction to league/commonmarkColin O'Dell
 
Serverless, The Middy Way - Workshop
Serverless, The Middy Way - WorkshopServerless, The Middy Way - Workshop
Serverless, The Middy Way - WorkshopLuciano Mammino
 
Import golang; struct microservice
Import golang; struct microserviceImport golang; struct microservice
Import golang; struct microserviceGiulio De Donato
 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hopeMarcus Ramberg
 
Php Documentor The Beauty And The Beast
Php Documentor The Beauty And The BeastPhp Documentor The Beauty And The Beast
Php Documentor The Beauty And The BeastBastian Feder
 
AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)
AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)
AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)Amazon Web Services
 
Automatisation in development and testing - within budget
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budgetDavid Lukac
 
SH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptx
SH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptxSH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptx
SH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptxMongoDB
 
Remote Config REST API and Versioning
Remote Config REST API and VersioningRemote Config REST API and Versioning
Remote Config REST API and VersioningJumpei Matsuda
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsMongoDB
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsMongoDB
 
Building full-stack Node.js web apps with Visual Studio Code
Building full-stack Node.js web apps with Visual Studio CodeBuilding full-stack Node.js web apps with Visual Studio Code
Building full-stack Node.js web apps with Visual Studio CodeMicrosoft Tech Community
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSAntonio Peric-Mazar
 
Powering Microservices with Docker, Kubernetes, Kafka, and MongoDB
Powering Microservices with Docker, Kubernetes, Kafka, and MongoDBPowering Microservices with Docker, Kubernetes, Kafka, and MongoDB
Powering Microservices with Docker, Kubernetes, Kafka, and MongoDBMongoDB
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Hugo Hamon
 

Similar to CommonMark: Markdown Done Right - ZendCon 2017 (20)

CommonMark: Markdown Done Right
CommonMark: Markdown Done RightCommonMark: Markdown Done Right
CommonMark: Markdown Done Right
 
ngManila - Codename: Fireball - Hello World in Angular
ngManila - Codename: Fireball - Hello World in AngularngManila - Codename: Fireball - Hello World in Angular
ngManila - Codename: Fireball - Hello World in Angular
 
Introduction to league/commonmark
Introduction to league/commonmarkIntroduction to league/commonmark
Introduction to league/commonmark
 
Serverless, The Middy Way - Workshop
Serverless, The Middy Way - WorkshopServerless, The Middy Way - Workshop
Serverless, The Middy Way - Workshop
 
Import golang; struct microservice
Import golang; struct microserviceImport golang; struct microservice
Import golang; struct microservice
 
Mojolicious
MojoliciousMojolicious
Mojolicious
 
MongoDB and Node.js
MongoDB and Node.jsMongoDB and Node.js
MongoDB and Node.js
 
Mojolicious - A new hope
Mojolicious - A new hopeMojolicious - A new hope
Mojolicious - A new hope
 
Php Documentor The Beauty And The Beast
Php Documentor The Beauty And The BeastPhp Documentor The Beauty And The Beast
Php Documentor The Beauty And The Beast
 
AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)
AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)
AWS re:Invent 2016: Amazon ECR Deep Dive on Image Optimization (CON401)
 
Automatisation in development and testing - within budget
Automatisation in development and testing - within budgetAutomatisation in development and testing - within budget
Automatisation in development and testing - within budget
 
SH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptx
SH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptxSH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptx
SH 1 - SES 4 - Microservices - Andrew Morgan TLV.pptx
 
Remote Config REST API and Versioning
Remote Config REST API and VersioningRemote Config REST API and Versioning
Remote Config REST API and Versioning
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.js
 
Webinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.jsWebinar: Building Your First App in Node.js
Webinar: Building Your First App in Node.js
 
Building full-stack Node.js web apps with Visual Studio Code
Building full-stack Node.js web apps with Visual Studio CodeBuilding full-stack Node.js web apps with Visual Studio Code
Building full-stack Node.js web apps with Visual Studio Code
 
Building Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJSBuilding Single Page Application (SPA) with Symfony2 and AngularJS
Building Single Page Application (SPA) with Symfony2 and AngularJS
 
Powering Microservices with Docker, Kubernetes, Kafka, and MongoDB
Powering Microservices with Docker, Kubernetes, Kafka, and MongoDBPowering Microservices with Docker, Kubernetes, Kafka, and MongoDB
Powering Microservices with Docker, Kubernetes, Kafka, and MongoDB
 
The Berkshelf Way
The Berkshelf WayThe Berkshelf Way
The Berkshelf Way
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 

More from Colin O'Dell

Demystifying Unicode - Longhorn PHP 2021
Demystifying Unicode - Longhorn PHP 2021Demystifying Unicode - Longhorn PHP 2021
Demystifying Unicode - Longhorn PHP 2021Colin O'Dell
 
Releasing High Quality Packages - Longhorn PHP 2021
Releasing High Quality Packages - Longhorn PHP 2021Releasing High Quality Packages - Longhorn PHP 2021
Releasing High Quality Packages - Longhorn PHP 2021Colin O'Dell
 
Releasing High Quality PHP Packages - ConFoo Montreal 2019
Releasing High Quality PHP Packages - ConFoo Montreal 2019Releasing High Quality PHP Packages - ConFoo Montreal 2019
Releasing High Quality PHP Packages - ConFoo Montreal 2019Colin O'Dell
 
Debugging Effectively - ConFoo Montreal 2019
Debugging Effectively - ConFoo Montreal 2019Debugging Effectively - ConFoo Montreal 2019
Debugging Effectively - ConFoo Montreal 2019Colin O'Dell
 
Automating Deployments with Deployer - php[world] 2018
Automating Deployments with Deployer - php[world] 2018Automating Deployments with Deployer - php[world] 2018
Automating Deployments with Deployer - php[world] 2018Colin O'Dell
 
Releasing High-Quality Packages - php[world] 2018
Releasing High-Quality Packages - php[world] 2018Releasing High-Quality Packages - php[world] 2018
Releasing High-Quality Packages - php[world] 2018Colin O'Dell
 
Debugging Effectively - DrupalCon Nashville 2018
Debugging Effectively - DrupalCon Nashville 2018Debugging Effectively - DrupalCon Nashville 2018
Debugging Effectively - DrupalCon Nashville 2018Colin O'Dell
 
Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017Colin O'Dell
 
Debugging Effectively - All Things Open 2017
Debugging Effectively - All Things Open 2017Debugging Effectively - All Things Open 2017
Debugging Effectively - All Things Open 2017Colin O'Dell
 
Hacking Your Way To Better Security - DrupalCon Baltimore 2017
Hacking Your Way To Better Security - DrupalCon Baltimore 2017Hacking Your Way To Better Security - DrupalCon Baltimore 2017
Hacking Your Way To Better Security - DrupalCon Baltimore 2017Colin O'Dell
 
Debugging Effectively - PHP UK 2017
Debugging Effectively - PHP UK 2017Debugging Effectively - PHP UK 2017
Debugging Effectively - PHP UK 2017Colin O'Dell
 
Debugging Effectively - SunshinePHP 2017
Debugging Effectively - SunshinePHP 2017Debugging Effectively - SunshinePHP 2017
Debugging Effectively - SunshinePHP 2017Colin O'Dell
 
Automating Your Workflow with Gulp.js - php[world] 2016
Automating Your Workflow with Gulp.js - php[world] 2016Automating Your Workflow with Gulp.js - php[world] 2016
Automating Your Workflow with Gulp.js - php[world] 2016Colin O'Dell
 
Rise of the Machines: PHP and IoT - php[world] 2016
Rise of the Machines: PHP and IoT - php[world] 2016Rise of the Machines: PHP and IoT - php[world] 2016
Rise of the Machines: PHP and IoT - php[world] 2016Colin O'Dell
 
Debugging Effectively - ZendCon 2016
Debugging Effectively - ZendCon 2016Debugging Effectively - ZendCon 2016
Debugging Effectively - ZendCon 2016Colin O'Dell
 
Hacking Your Way to Better Security - ZendCon 2016
Hacking Your Way to Better Security - ZendCon 2016Hacking Your Way to Better Security - ZendCon 2016
Hacking Your Way to Better Security - ZendCon 2016Colin O'Dell
 
Hacking Your Way to Better Security - PHP South Africa 2016
Hacking Your Way to Better Security - PHP South Africa 2016Hacking Your Way to Better Security - PHP South Africa 2016
Hacking Your Way to Better Security - PHP South Africa 2016Colin O'Dell
 
Debugging Effectively - DrupalCon Europe 2016
Debugging Effectively - DrupalCon Europe 2016Debugging Effectively - DrupalCon Europe 2016
Debugging Effectively - DrupalCon Europe 2016Colin O'Dell
 
Debugging Effectively - Frederick Web Tech 9/6/16
Debugging Effectively - Frederick Web Tech 9/6/16Debugging Effectively - Frederick Web Tech 9/6/16
Debugging Effectively - Frederick Web Tech 9/6/16Colin O'Dell
 
Debugging Effectively
Debugging EffectivelyDebugging Effectively
Debugging EffectivelyColin O'Dell
 

More from Colin O'Dell (20)

Demystifying Unicode - Longhorn PHP 2021
Demystifying Unicode - Longhorn PHP 2021Demystifying Unicode - Longhorn PHP 2021
Demystifying Unicode - Longhorn PHP 2021
 
Releasing High Quality Packages - Longhorn PHP 2021
Releasing High Quality Packages - Longhorn PHP 2021Releasing High Quality Packages - Longhorn PHP 2021
Releasing High Quality Packages - Longhorn PHP 2021
 
Releasing High Quality PHP Packages - ConFoo Montreal 2019
Releasing High Quality PHP Packages - ConFoo Montreal 2019Releasing High Quality PHP Packages - ConFoo Montreal 2019
Releasing High Quality PHP Packages - ConFoo Montreal 2019
 
Debugging Effectively - ConFoo Montreal 2019
Debugging Effectively - ConFoo Montreal 2019Debugging Effectively - ConFoo Montreal 2019
Debugging Effectively - ConFoo Montreal 2019
 
Automating Deployments with Deployer - php[world] 2018
Automating Deployments with Deployer - php[world] 2018Automating Deployments with Deployer - php[world] 2018
Automating Deployments with Deployer - php[world] 2018
 
Releasing High-Quality Packages - php[world] 2018
Releasing High-Quality Packages - php[world] 2018Releasing High-Quality Packages - php[world] 2018
Releasing High-Quality Packages - php[world] 2018
 
Debugging Effectively - DrupalCon Nashville 2018
Debugging Effectively - DrupalCon Nashville 2018Debugging Effectively - DrupalCon Nashville 2018
Debugging Effectively - DrupalCon Nashville 2018
 
Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017Rise of the Machines: PHP and IoT - ZendCon 2017
Rise of the Machines: PHP and IoT - ZendCon 2017
 
Debugging Effectively - All Things Open 2017
Debugging Effectively - All Things Open 2017Debugging Effectively - All Things Open 2017
Debugging Effectively - All Things Open 2017
 
Hacking Your Way To Better Security - DrupalCon Baltimore 2017
Hacking Your Way To Better Security - DrupalCon Baltimore 2017Hacking Your Way To Better Security - DrupalCon Baltimore 2017
Hacking Your Way To Better Security - DrupalCon Baltimore 2017
 
Debugging Effectively - PHP UK 2017
Debugging Effectively - PHP UK 2017Debugging Effectively - PHP UK 2017
Debugging Effectively - PHP UK 2017
 
Debugging Effectively - SunshinePHP 2017
Debugging Effectively - SunshinePHP 2017Debugging Effectively - SunshinePHP 2017
Debugging Effectively - SunshinePHP 2017
 
Automating Your Workflow with Gulp.js - php[world] 2016
Automating Your Workflow with Gulp.js - php[world] 2016Automating Your Workflow with Gulp.js - php[world] 2016
Automating Your Workflow with Gulp.js - php[world] 2016
 
Rise of the Machines: PHP and IoT - php[world] 2016
Rise of the Machines: PHP and IoT - php[world] 2016Rise of the Machines: PHP and IoT - php[world] 2016
Rise of the Machines: PHP and IoT - php[world] 2016
 
Debugging Effectively - ZendCon 2016
Debugging Effectively - ZendCon 2016Debugging Effectively - ZendCon 2016
Debugging Effectively - ZendCon 2016
 
Hacking Your Way to Better Security - ZendCon 2016
Hacking Your Way to Better Security - ZendCon 2016Hacking Your Way to Better Security - ZendCon 2016
Hacking Your Way to Better Security - ZendCon 2016
 
Hacking Your Way to Better Security - PHP South Africa 2016
Hacking Your Way to Better Security - PHP South Africa 2016Hacking Your Way to Better Security - PHP South Africa 2016
Hacking Your Way to Better Security - PHP South Africa 2016
 
Debugging Effectively - DrupalCon Europe 2016
Debugging Effectively - DrupalCon Europe 2016Debugging Effectively - DrupalCon Europe 2016
Debugging Effectively - DrupalCon Europe 2016
 
Debugging Effectively - Frederick Web Tech 9/6/16
Debugging Effectively - Frederick Web Tech 9/6/16Debugging Effectively - Frederick Web Tech 9/6/16
Debugging Effectively - Frederick Web Tech 9/6/16
 
Debugging Effectively
Debugging EffectivelyDebugging Effectively
Debugging Effectively
 

Recently uploaded

Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio, Inc.
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureDinusha Kumarasiri
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 

Recently uploaded (20)

Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed DataAlluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
Alluxio Monthly Webinar | Cloud-Native Model Training on Distributed Data
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Implementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with AzureImplementing Zero Trust strategy with Azure
Implementing Zero Trust strategy with Azure
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 

CommonMark: Markdown Done Right - ZendCon 2017

  • 2. COLIN O’DELL Creator & Maintainer of league/commonmark Lead Web Developer at Unleashed Technologies Author of PHP 7 Migration Guide e-book @colinodel l
  • 3. LEAGUE/COMMONMARK A well-written, super-configurable Markdown parser for PHP based on the CommonMark spec. @colinodel l
  • 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 @colinodel l
  • 5. HISTORY OF MARKDOWN Hello ZendCon! -------------- Markdown is **awesome**! 1. Foo 2. Bar 3. Baz Wikipedia entry: <https://en.wikipedia.org/wiki/Markdown> @colinodel l
  • 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 @colinodel l
  • 7. 68+ DIFFERENT FLAVORS Source: https://github.com/markdown/markdown.github.com/wiki/Implementations Actuarius Blackfriday BlueCloth BlueFeather cebe/markdown CocoaMarkdown CommonMark 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 @colinodel l
  • 9. WHY IS IT NEEDED? *I love Markdown* <p><em>I love Markdown</em></p> @colinodel l
  • 10. WHY IS IT NEEDED? *I *love* Markdown* @colinodel l
  • 11. WHY IS IT NEEDED? Source: http://johnmacfarlane.net/babelmark2/
  • 12. 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/ @colinodel l
  • 13. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  • 14. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  • 15. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  • 16. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  • 17. WHY IS IT NEEDED? 1. > Hello World! ------ Source: http://johnmacfarlane.net/babelmark2/
  • 18. 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”)  624 examples @colinodel l
  • 19.
  • 20.
  • 21.
  • 22.
  • 23. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 24. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 25. ADDING LEAGUE/COMMONMARK $ composer require league/commonmark:^0.15 <?php $converter = new CommonMarkConverter(); echo $converter->convertToHtml('Hello **ZendCon!**'); @colinodel l
  • 27. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 28. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 33. CONVERSION PROCESS Markdow n AST HTMLRenderParse Add your own custom parser, processor, or renderer @colinodel l
  • 34. EXAMPLE 1: CUSTOM PARSER <http://www.zendcon.com> <a href="http://www.zendcon.com"> http://www.zendcon.com </a> <@colinodell> <a href="https://twitter.com/colinodell"> @colinodell </a> @colinodel l
  • 35. class TwitterUsernameAutolinkParser extends AbstractInlineParser { public function getCharacters() { return ['<']; } public function parse(InlineParserContext $inlineContext) { // TODO } } @colinodel l
  • 36. CURSOR Learning CommonMark with <@colinodell>! public function getCharacters() { return ['<']; } @colinodel l
  • 37. class TwitterUsernameAutolinkParser extends AbstractInlineParser { public function getCharacters() { return ['<']; } public function parse(InlineParserContext $inlineContext) { $cursor = $inlineContext->getCursor(); } } @colinodel l
  • 38. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count) @colinodel l
  • 39. CURSOR Learning CommonMark with <@colinodell>! getCharacter() getFirstNonSpaceCharacter( ) getRemainder() getLine() getPosition() advance() advanceBy($count) advanceBySpaceOrTab() advanceWhileMatches($char ) advanceToFirstNonSpace() isIndented() isAtEnd() match($regex) peek($count) @colinodel l
  • 40. 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_]+>/ @colinodel l
  • 41. 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; } } @colinodel l
  • 42. $environment = Environment::createCommonMarkEnvironment(); $environment->addInlineParser( new TwitterHandleParser() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml( "Follow <@colinodell> on Twitter!" ); @colinodel l
  • 43. EXAMPLE 2: CUSTOM AST PROCESSOR <document> <paragraph> <link destination="http://www.zendcon.com"> <text>http://www.zendcon.com</text> </link> </paragraph> </document> <document> <paragraph> <link destination="https://bit.ly/foo"> <text>http://www.zendcon.com</text> </link> </paragraph> </document> @colinodel l
  • 44. 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); } } } } @colinodel l
  • 45. $environment = Environment::createCommonMarkEnvironment(); $environment->addDocumentProcessor( new ShortenLinkProcessor() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml( "Schedule: <http://www.zendcon.com/schedule>" ); EXAMPLE 2: CUSTOM AST PROCESSOR @colinodel l
  • 46. 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" /> @colinodel l
  • 47. EXAMPLE 3: CUSTOM RENDERER class ImageHorizontalRuleRenderer implements BlockRendererInterface { public function render(...) { return new HtmlElement('img', ['src' => 'hr.png']); } } @colinodel l
  • 48. $environment = Environment::createCommonMarkEnvironment(); $environment->addBlockRenderer( LeagueCommonMarkBlockElementThematicBreak::class, new ImageHorizontalRuleRenderer() ); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml("Hello World!nn-----"); EXAMPLE 3: CUSTOM RENDERER @colinodel l
  • 49. 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()]; } } @colinodel l
  • 50. BUNDLING INTO AN EXTENSION $environment = Environment::createCommonMarkEnvironment(); $environment->addExtension(new MyCustomExtension()); $converter = new CommonMarkConverter($environment); $html = $converter->convertToHtml("..."); @colinodel l
  • 51. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 52. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 53. WELL-TESTED  94% code coverage  Functional tests  All 624 spec examples  Library of regression tests  Unit tests  Cursor  Environment  Utility classes @colinodel l
  • 54. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 55. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 56. PERFORMANCE 0 20 40 60 80 Parsedown cebe/markdown gfm PHP Markdown Extra league/commonmark Time (ms) league/commonmark is ~22-24ms slower PHP 5.6 PHP 7.1 Tips: • Choose library based on your needs • Cache rendered HTML (100% boost) • Use PHP 7 (50% boost) • Optimize custom functionality @colinodel l
  • 57. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 58. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 59. STABILITY  Current version: 0.15.6  Conforms to CommonMark spec 0.28  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 are documented (see UPGRADING.md) @colinodel l
  • 60. FEATURES  100% compliance with the CommonMark spec  Easy to implement  Easy to customize  Well-tested  Decent performance  (Relatively) stable @colinodel l
  • 61. Installation & Documentation: http://github.com/thephpleague/commonmark Learn More About CommonMark: http://commonmark.org Slides / Feedback: https://joind.in/talk/8da74 @colinodell

Editor's Notes

  1. So what is league/commonmark?
  2. The league/commonmark library It basically takes Markdown in and spits HTML out. And it does so in a way that’s compliant with the CommonMark spec. OUT: Now I’ve mentioned the word CommonMark a few times, but what is that?
  3. In collaboration with Aaron Swartz
  4. 2. Informal; not like XML and XHTML which reject data simply because it fails to adhere to strict, unforgiving standards
  5. Straight-forward example of emphasizing text
  6. What happens if we add two asterisks?
  7. Babelmark2 John MacFarlane, CommonMark spec maintainer Like 3V4L, but for Markdown
  8. Whole string emphasized with nested inner emphasis, as you’d expect Another approach some parsers take is two separate emphasis elements Kinda makes sense What’s really strange and unexpected 3 other ways of parsing this (22%)
  9. Actually 15 different ways that parsers interpret this OUTRO: The CommonMark standard is designed to eliminate this ambiguity so that your Markdown is handled in a logical, predictable fashion
  10. Actually 15 different ways that parsers interpret this 1/4 OUTRO: The CommonMark standard is designed to eliminate this ambiguity so that your Markdown is handled in a logical, predictable fashion
  11. 2/4
  12. 3/4
  13. Actually 15 different ways that parsers interpret this OUTRO: The CommonMark standard is designed to eliminate this ambiguity so that your Markdown is handled in a logical, predictable fashion
  14. We’re all familiar with the usual markdown syntax This specification dictates exactly how compliant parsers should handle Markdown input It includes Look at the spec
  15. What’s really cool: - Examples can easily be parsed out and tested against by our Markdown library!
  16. Several integrations for this library built by the community
  17. We have a URL we want to link to using the standard autolinking syntax Wrapped with a less-than and greater-than sign “A” tag with href and text label of the URL Show how our engine does this behind-the-scenes
  18. Start off with Markdown input Run it through the various sub-parsers which results in an Abstract Syntax Tree
  19. Also known as an AST Tree structure of PHP objects, each representing a certain type of element For easier visualization I’m showing what these PHP objects MIGHT look like if we showed their data as XML Once we’ve got the final AST, we pass that along to the renderers…
  20. …which convert the AST into HTML Now what’s really cool is that…
  21. You can hook into any of these three aspects, adding “your own custom…” THREE EXAMPLES Now let’s go back to our autolink example
  22. What if we wanted to add similar autolinking functionality, but for Twitter handles? For example, say we want to enclose the Twitter handle in a similar fashion… which results in a link to that profile page Let me show you how simple it is to add this feature
  23. Simply create a sub-parser Tell the main parser to stop whenever a less-than sign is encountered When encountered, control is transferred to parse()
  24. Cursor is a simple yet powerful wrapper around the current line Stores current line’s text and current position being parsed Because we’ve told the engine we’re interested in less-than characters…
  25. Simply create a sub-parser Tell the main parser to stop whenever a less-than sign is encountered When encountered, control is transferred to parse()
  26. When control is passed into parse() method, we can use these specially-design methods to Parse the string at that location Cursor provides several high-optimized UTF-8 aware methods for Markdown parsing DESCRIBE METHODS HOW TO IMPLEMENT OUR TWITTER AUTOLINK PARSER?
  27. WE COULD TRY THIS
  28. BETTER
  29. That’s it! Now the APIs and methods might be unfamiliar, but hopefully you can see how features can be added seemlesly with only a few lines of code
  30. Match this regular expression Extract just the username from the matched text That’s it! Now the APIs and methods might be unfamiliar, but hopefully you can see how features can be added seemlesly with only a few lines of code
  31. What if we wanted to automatically shorten URLs with a service like bitly?
  32. Guaranteed to be compatible with all other CommonMark parsers in other languages
  33. Blinking your eye is 100ms
  34. You can find the library on Packagist under league/commonmark Installation instructions & documentation can be found Hopefully you find this library useful and can try it out in your next project. Thank you so much!