Add HeaderSlug configurable

Adds HeaderSlug configurable, with the option for the slug function
to be customised.

Co-authored-by: netniV <netniv@hotmail.com>
This commit is contained in:
Aidan Woods 2020-05-04 22:02:20 +01:00
parent 74df602863
commit e332b4710a
No known key found for this signature in database
GPG Key ID: 9A6A8EFAA512BBB9
7 changed files with 156 additions and 2 deletions

View File

@ -5,6 +5,7 @@ namespace Erusev\Parsedown\Components\Blocks;
use Erusev\Parsedown\AST\Handler;
use Erusev\Parsedown\AST\StateRenderable;
use Erusev\Parsedown\Components\Block;
use Erusev\Parsedown\Configurables\HeaderSlug;
use Erusev\Parsedown\Configurables\StrictMode;
use Erusev\Parsedown\Html\Renderables\Element;
use Erusev\Parsedown\Parsedown;
@ -96,9 +97,16 @@ final class Header implements Block
return new Handler(
/** @return Element */
function (State $State) {
$HeaderSlug = $State->get(HeaderSlug::class);
$attributes = (
$HeaderSlug->isEnabled()
? ['id' => $HeaderSlug->transform($this->text())]
: []
);
return new Element(
'h' . \strval($this->level()),
[],
$attributes,
$State->applyTo(Parsedown::line($this->text(), $State))
);
}

View File

@ -6,6 +6,7 @@ use Erusev\Parsedown\AST\Handler;
use Erusev\Parsedown\AST\StateRenderable;
use Erusev\Parsedown\Components\AcquisitioningBlock;
use Erusev\Parsedown\Components\Block;
use Erusev\Parsedown\Configurables\HeaderSlug;
use Erusev\Parsedown\Html\Renderables\Element;
use Erusev\Parsedown\Parsedown;
use Erusev\Parsedown\Parsing\Context;
@ -88,9 +89,16 @@ final class SetextHeader implements AcquisitioningBlock
return new Handler(
/** @return Element */
function (State $State) {
$HeaderSlug = $State->get(HeaderSlug::class);
$attributes = (
$HeaderSlug->isEnabled()
? ['id' => $HeaderSlug->transform($this->text())]
: []
);
return new Element(
'h' . \strval($this->level()),
[],
$attributes,
$State->applyTo(Parsedown::line($this->text(), $State))
);
}

View File

@ -0,0 +1,64 @@
<?php
namespace Erusev\Parsedown\Configurables;
use Erusev\Parsedown\Configurable;
final class HeaderSlug implements Configurable
{
/** @var bool */
private $enabled = false;
/** @var \Closure(string):string */
private $slugCallback;
/**
* @param bool $enabled
* @param (\Closure(string):string)|null $slugCallback
*/
public function __construct($enabled, $slugCallback = null)
{
$this->enabled = $enabled;
if (! isset($slugCallback)) {
$this->slugCallback = function (string $text): string {
$slug = \mb_strtolower($text);
$slug = \str_replace(' ', '-', $slug);
$slug = \preg_replace('/[^\p{L}\p{N}\p{M}-]+/u', '', $slug);
return $slug;
};
} else {
$this->slugCallback = $slugCallback;
}
}
/** @return bool */
public function isEnabled()
{
return $this->enabled;
}
public function transform(string $text): string
{
return ($this->slugCallback)($text);
}
/** @param \Closure(string):string $slugCallback */
public static function withCallback($slugCallback): self
{
return new self(true, $slugCallback);
}
/** @return self */
public static function enabled()
{
return new self(true);
}
/** @return self */
public static function initial()
{
return new self(false);
}
}

View File

@ -6,6 +6,7 @@ use Erusev\Parsedown\Components\Blocks\Markup as BlockMarkup;
use Erusev\Parsedown\Components\Inlines\Markup as InlineMarkup;
use Erusev\Parsedown\Configurables\BlockTypes;
use Erusev\Parsedown\Configurables\Breaks;
use Erusev\Parsedown\Configurables\HeaderSlug;
use Erusev\Parsedown\Configurables\InlineTypes;
use Erusev\Parsedown\Configurables\SafeMode;
use Erusev\Parsedown\Configurables\StrictMode;
@ -59,6 +60,7 @@ class ParsedownTest extends TestCase
new SafeMode(\substr($test, 0, 3) === 'xss'),
new StrictMode(\substr($test, 0, 6) === 'strict'),
new Breaks(\substr($test, 0, 14) === 'breaks_enabled'),
new HeaderSlug(\substr($test, 0, 4) === 'slug'),
]));
$actualMarkup = $Parsedown->toHtml($markdown);

View File

@ -0,0 +1,10 @@
<h1 id="foo">foo</h1>
<h1 id="foo-bar">foo bar</h1>
<h1 id="foobar">foo_bar</h1>
<h1 id="foobar">foo+bar</h1>
<h1 id="2rer0ගම්මැද්ද-v-force-ඉනොවේශන්-නේෂන්-සඳහා-එවූ-නි">2rer*(0👍ගම්මැද්ද V FORCE ඉනොවේශන් නේෂන් සඳහා එවූ නි</h1>
<h2 id="foo">foo</h2>
<h2 id="foo-bar">foo bar</h2>
<h2 id="foobar">foo_bar</h2>
<h2 id="foobar">foo+bar</h2>
<h2 id="2rer0ගම්මැද්ද-v-force-ඉනොවේශන්-නේෂන්-සඳහා-එවූ-නි">2rer*(0👍ගම්මැද්ද V FORCE ඉනොවේශන් නේෂන් සඳහා එවූ නි</h2>

View File

@ -0,0 +1,24 @@
# foo
# foo bar
# foo_bar
# foo+bar
# 2rer*(0👍ගම්මැද්ද V FORCE ඉනොවේශන් නේෂන් සඳහා එවූ නි
foo
---
foo bar
---
foo_bar
---
foo+bar
---
2rer*(0👍ගම්මැද්ද V FORCE ඉනොවේශන් නේෂන් සඳහා එවූ නි
---

View File

@ -0,0 +1,38 @@
<?php
namespace Erusev\Parsedown\Tests\Configurables;
use Erusev\Parsedown\Configurables\HeaderSlug;
use Erusev\Parsedown\State;
use PHPUnit\Framework\TestCase;
final class HeaderSlugTest extends TestCase
{
/**
* @return void
* @throws \PHPUnit\Framework\ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function testNamedConstructor()
{
$State = new State([HeaderSlug::enabled()]);
$this->assertSame(true, $State->get(HeaderSlug::class)->isEnabled());
}
/**
* @return void
* @throws \PHPUnit\Framework\ExpectationFailedException
* @throws \SebastianBergmann\RecursionContext\InvalidArgumentException
*/
public function testCustomCallback()
{
$HeaderSlug = HeaderSlug::withCallback(function (string $t): string {
return \preg_replace('/[^A-Za-z0-9]++/', '_', $t);
});
$this->assertSame(
'foo_bar',
$HeaderSlug->transform('foo bar')
);
}
}