Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
8 / 8
CRAP
100.00% covered (success)
100.00%
1 / 1
BladeDownProcessor
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
8 / 8
10
100.00% covered (success)
100.00%
1 / 1
 render
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 preprocess
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 postprocess
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 run
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 get
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 lineStartsWithDirective
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 processLine
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Hyde\Markdown\Processing;
6
7use Hyde\Markdown\Contracts\MarkdownPostProcessorContract;
8use Hyde\Markdown\Contracts\MarkdownPreProcessorContract;
9use Illuminate\Support\Facades\Blade;
10
11use function html_entity_decode;
12use function str_starts_with;
13use function strtolower;
14use function array_map;
15use function explode;
16use function implode;
17use function substr;
18use function trim;
19use function e;
20
21/**
22 * Markdown Processor to render Laravel Blade within Markdown files.
23 *
24 * Works on a line-by-line basis by searching for a line starting with the directive.
25 * The preprocessor expands the directive to an HTML comment. The post-processor parses it.
26 *
27 * @example: [Blade]: {{ time() }}
28 *
29 * @example: [Blade]: @include('path/to/view.blade.php')
30 *
31 * @phpstan-consistent-constructor
32 */
33class BladeDownProcessor implements MarkdownPreProcessorContract, MarkdownPostProcessorContract
34{
35    protected string $html;
36    protected string $output;
37
38    protected array $pageData = [];
39
40    public static function render(string $html, array $pageData = []): string
41    {
42        return (new static(static::preprocess($html), $pageData))->run()->get();
43    }
44
45    public static function preprocess(string $markdown): string
46    {
47        return implode("\n", array_map(function (string $line): string {
48            return str_starts_with(strtolower($line), strtolower('[Blade]:'))
49                ? '<!-- HYDE'.trim(e($line)).' -->'
50                : $line;
51        }, explode("\n", $markdown)));
52    }
53
54    public static function postprocess(string $html, array $pageData = []): string
55    {
56        return (new static($html, $pageData))->run()->get();
57    }
58
59    public function __construct(string $html, ?array $pageData = [])
60    {
61        $this->html = $html;
62        $this->pageData = $pageData;
63    }
64
65    public function run(): static
66    {
67        $this->output = implode("\n", array_map(function (string $line): string {
68            return $this->lineStartsWithDirective($line)
69                ? $this->processLine($line)
70                : $line;
71        }, explode("\n", $this->html)));
72
73        return $this;
74    }
75
76    public function get(): string
77    {
78        return $this->output;
79    }
80
81    protected function lineStartsWithDirective(string $line): bool
82    {
83        return str_starts_with(strtolower($line), '<!-- hyde[blade]:');
84    }
85
86    protected function processLine(string $line): string
87    {
88        return Blade::render(
89            substr(substr(html_entity_decode($line), 18), 0, -4),
90            $this->pageData
91        );
92    }
93}