nessworthy / parsedown-extension-manager
Extend Parsedown in a more SOLID way.
Requires
- php: >=7.1
- erusev/parsedown: ^1.7
- nessworthy/parsedown-extension: 1.0.1
Requires (Dev)
- phpunit/phpunit: 7.4.4
- roave/security-advisories: dev-master
README
A tiny project which introduces a new way to create and use markdown extensions with erusev/parsedown!
Requirements
- PHP 7.1
Installation
It's a composer installation away!
composer require nessworthy/parsedown-extension-manager
Why?
Each extension added to Parsedown must be done by extending it, registering the extension in a few places, and adding 1-3 new methods in the extended class.
After adding in a few extensions the original way, I grew a little frustrated at how "vertical" the markdown class was becoming.
So, I decided to change the way extensions could be registered.
What's new?
Extensions can be represented as concrete classes of one of two interfaces: ParsedownBlockExtension
, or ParsedownInlineExtension
.
Each extension is then separately instantiated and registered to your Nessworthy\ParsedownExtensionManager\Parsedown
instance by using the added
registerBlockExtension
or registerInlineExtension
and passing your extension through.
Parsedown will use your extensions in the same way as it normally would with the benefit of each extension being isolated and separately extendable!
Usage Example
Step 1: Create your Extension!
Extensions can either implement \Nessworthy\ParsedownExtensionManager\ParsedownInlineExtension
or
\Nessworthy\ParsedownExtensionManager\ParsedownBlockExtension
. Both expect methods which mirror closely to how you would
add extensions normally.
<?php use \Nessworthy\ParsedownExtensionManager\Parsedown; /** * This is an implementation of the "Add Inline Element" example in the parsedown docs. * @see https://github.com/erusev/parsedown/wiki/Tutorial:-Create-Extensions#add-inline-element */ class ExampleInlineExtension implements \Nessworthy\ParsedownExtensionManager\ParsedownInlineExtension { public function getStartingCharacter(): string { return '{'; } public function run(array $excerpt): ?array { if (preg_match('/^{c:([#\w]\w+)}(.*?){\/c}/', $excerpt['text'], $matches)) { return [ 'extent' => strlen($matches[0]), 'element' => [ 'name' => 'span', 'text' => $matches[2], 'attributes' => [ 'style' => 'color: ' . $matches[1], ], ], ]; } return null; } }
Step 2: Instantiate & Register your Extension!
<?php // Create your Parsedown instance. $parsedown = new \Nessworthy\ParsedownExtensionManager\Parsedown(); // Register your Parsedown extensions. $parsedown->registerInlineExtension(new ExampleInlineExtension()); // Use Parsedown as you normally would! $parsedown->parse('Hello {c:#FF00000}world{/c}!'); // "<p>Hello <span style="color: #FF0000">world!</span></p>
What's the catch?
Mm, good question. Let me know and I'll put it here!
Parsedown is still fundamentally the same, with the added functionality of seperate extension registration. You can still extend this class and add parsedown extensions the original way!
Ignorance aside, this library does leverage __call
and tries to do so
as sanely as possible.
In addition, because this is yet another extension of Parsedown, it won't work out of the box with any of the other Parsedown extensions out there. However, it's possible to simply convert other Parsedown extensions to work with this library instead!
Distributing Extensions
If you fancy creating and sharing extensions of your own, feel free to use the nessworthy\parsedown-extension
metapackage instead which only contains the interfaces you need to implement.
Extension Docs
I won't go into detail on how to write Parsedown Extensions here - the parsedown documentation does a good job of explaining what you need to do to add markdown extensions. The returned data from your methods should still be the same as if you had just extended markdown in the original way.
ParsedownInlineExtension
Inline extensions require two methods:
getStartingCharacter(): string
- Expects you return a single character which tells Parsedown to start using your extension when it's found in the markdown body.run(array $excerpt): ?array
- The equivalent of Parsedown'sinlineYourExtension($excerpt)
extension method.
ParsedownBlockExtension
Block extensions always require the following four methods:
getStartingCharacter(): string
- Expects you return a single character which tells Parsedown to start using your extension when it's found in the markdown body.start($line, array $block = null): ?array
- The equivalent of Parsedown'sblockYourExtension($line, $block)
method.continue($line, array $block): ?array
- The equivalent of Parsedown'sblockYourExtensionContinue($line, $block)
method.complete(array $block): ?array
- The equivalent of Parsedown'sblockYourExtensionComplete($block)
method.
What's next?
- More accurate written tests! (e.g. to account for pre-registered inline special characters and not yet registered ones)