Passed
Push — master ( fd9522...301e3e )
by Caen
03:20 queued 14s
created

CodeblockFilepathProcessor::process()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 4
nop 1
dl 0
loc 19
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
namespace Hyde\Framework\Modules\Markdown;
4
5
use Hyde\Framework\Contracts\MarkdownPostProcessorContract;
6
use Hyde\Framework\Contracts\MarkdownPreProcessorContract;
7
8
/**
9
 * Resolves file path comments found in Markdown code blocks into a neat badge shown in the top right corner.
10
 *
11
 * @see \Hyde\Framework\Testing\Feature\Services\Markdown\CodeblockFilepathProcessorTest
12
 */
13
class CodeblockFilepathProcessor implements MarkdownPreProcessorContract, MarkdownPostProcessorContract
14
{
15
    /**
16
     * Extract lines matching the shortcode pattern and replace them with meta-blocks that will be processed later.
17
     */
18
    public static function preprocess(string $markdown): string
19
    {
20
        $lines = explode("\n", $markdown);
21
22
        foreach ($lines as $index => $line) {
23
            if (static::lineMatchesPattern($line) && ! str_contains($line, '{"shortcodes": false}')) {
24
                // Add the meta-block two lines before the pattern, placing it just above the code block.
25
                // This prevents the meta-block from interfering with other processes.
26
                $lines[$index - 2] .= sprintf(
27
                    "\n<!-- HYDE[Filepath]%s -->",
28
                    trim(str_replace(static::$patterns, '', $line))
29
                );
30
31
                // Remove the original comment lines
32
                unset($lines[$index]);
33
                // Only unset the next line if it's empty
34
                if (trim($lines[$index + 1]) === '') {
35
                    unset($lines[$index + 1]);
36
                }
37
            }
38
        }
39
40
        return implode("\n", $lines);
41
    }
42
43
    /**
44
     * Process the meta-blocks added by the preprocessor, injecting the filepath badge template into the code block.
45
     */
46
    public static function postprocess(string $html): string
47
    {
48
        $lines = explode("\n", $html);
49
50
        /** @var int $index */
51
        foreach ($lines as $index => $line) {
52
            if (str_starts_with($line, '<!-- HYDE[Filepath]')) {
53
                $path = static::trimHydeDirective($line);
54
                unset($lines[$index]);
55
                $codeBlockLine = $index + 1;
56
                $label = static::resolveTemplate($path);
57
58
                $lines[$codeBlockLine] = str_contains($html, static::$torchlightKey)
59
                ? static::injectLabelToTorchlightCodeLine($label, $lines[$codeBlockLine])
60
                : static::injectLabelToCodeLine($label, $lines[$codeBlockLine]);
61
            }
62
        }
63
64
        return implode("\n", $lines);
65
    }
66
67
    protected static array $patterns = [
68
        '// filepath: ',
69
        '// Filepath: ',
70
        '# filepath: ',
71
        '# Filepath: ',
72
        '// filepath ',
73
        '// Filepath ',
74
        '# filepath ',
75
        '# Filepath ',
76
    ];
77
78
    protected static string $torchlightKey = '<!-- Syntax highlighted by torchlight.dev -->';
79
80
    protected static function lineMatchesPattern(string $line): bool
81
    {
82
        foreach (static::$patterns as $pattern) {
83
            if (str_starts_with($line, $pattern)) {
84
                return true;
85
            }
86
        }
87
88
        return false;
89
    }
90
91
    protected static function trimHydeDirective(string $line): string
92
    {
93
        return trim(str_replace('-->', '', str_replace(
94
            '<!-- HYDE[Filepath]',
95
            '',
96
            $line
97
        )));
98
    }
99
100
    protected static function resolveTemplate(string $path): string
101
    {
102
        return view('hyde::components.filepath-label', [
103
            'path' => $path,
104
        ])->render();
105
    }
106
107
    protected static function injectLabelToTorchlightCodeLine(string $label, string $lines): string
108
    {
109
        return str_replace(
110
            static::$torchlightKey,
111
            static::$torchlightKey.$label,
112
            $lines
113
        );
114
    }
115
116
    protected static function injectLabelToCodeLine(string $label, string $lines): string
117
    {
118
        return preg_replace(
119
            '/<pre><code class="language-(.*?)">/',
120
            '<pre><code class="language-$1">'.$label,
121
            $lines
122
        );
123
    }
124
}
125