Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
CodeblockFilepathProcessor
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
7 / 7
16
100.00% covered (success)
100.00%
1 / 1
 preprocess
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
5
 process
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
 lineMatchesPattern
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 trimHydeDirective
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 resolveTemplate
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 resolveTorchlightCodeLine
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 resolveCodeLine
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Hyde\Framework\Services\Markdown;
4
5/**
6 * @see \Tests\Feature\Services\Markdown\CodeblockFilepathProcessorTest
7 */
8class CodeblockFilepathProcessor
9{
10    public static function preprocess(string $markdown): string
11    {
12        $lines = explode("\n", $markdown);
13
14        foreach ($lines as $index => $line) {
15            if (static::lineMatchesPattern($line) && ! str_contains($line, '{"shortcodes": false}')) {
16                // Add the meta-block two lines before the pattern, placing it just above the code block.
17                // This prevents the meta-block from interfering with other processes.
18                $lines[$index - 2] .= sprintf("\n<!-- HYDE[Filepath]%s -->",
19                    trim(str_replace(static::$patterns, '', $line))
20                );
21
22                // Remove the original comment lines
23                unset($lines[$index]);
24                // Only unset the next line if it's empty
25                if (trim($lines[$index + 1]) === '') {
26                    unset($lines[$index + 1]);
27                }
28            }
29        }
30
31        return implode("\n", $lines);
32    }
33
34    public static function process(string $html): string
35    {
36        $lines = explode("\n", $html);
37
38        foreach ($lines as $index => $line) {
39            if (str_starts_with($line, '<!-- HYDE[Filepath]')) {
40                $path = static::trimHydeDirective($line);
41                unset($lines[$index]);
42                $codeBlockLine = $index + 1;
43                $label = static::resolveTemplate($path, $lines[$codeBlockLine]);
44
45                $lines[$codeBlockLine] = str_contains($html, static::$torchlightKey)
46                ? static::resolveTorchlightCodeLine($label, $lines[$codeBlockLine])
47                : static::resolveCodeLine($label, $lines[$codeBlockLine]);
48            }
49        }
50
51        return implode("\n", $lines);
52    }
53
54    protected static array $patterns = [
55        '// filepath: ',
56        '// Filepath: ',
57        '# filepath: ',
58        '# Filepath: ',
59        '// filepath ',
60        '// Filepath ',
61        '# filepath ',
62        '# Filepath ',
63    ];
64
65    protected static string $torchlightKey = '<!-- Syntax highlighted by torchlight.dev -->';
66
67    protected static function lineMatchesPattern(string $line): bool
68    {
69        foreach (static::$patterns as $pattern) {
70            if (str_starts_with($line, $pattern)) {
71                return true;
72            }
73        }
74
75        return false;
76    }
77
78    protected static function trimHydeDirective(string $line): string
79    {
80        return trim(str_replace('-->', '', str_replace(
81            '<!-- HYDE[Filepath]', '', $line))
82        );
83    }
84
85    protected static function resolveTemplate(string $path, string $line): string
86    {
87        $template = '<small class="filepath"><span class="sr-only">Filepath: </span>%s</small>';
88
89        return sprintf($template, $path, $line);
90    }
91
92    protected static function resolveTorchlightCodeLine(string $label, $lines): string|array
93    {
94        return str_replace(
95            static::$torchlightKey,
96            static::$torchlightKey.$label,
97            $lines
98        );
99    }
100
101    protected static function resolveCodeLine(string $label, $lines): string|array|null
102    {
103        return preg_replace(
104            '/<pre><code class="language-(.*?)">/',
105            '<pre><code class="language-$1">'.$label,
106            $lines
107        );
108    }
109}