Passed
Branch refactor-markdown-helper (02b3eb)
by Caen
04:15
created

ShortcodeProcessor   A

Complexity

Total Complexity 13

Size/Duplication

Total Lines 81
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 24
c 0
b 0
f 0
dl 0
loc 81
rs 10
wmc 13

10 Methods

Rating   Name   Duplication   Size   Complexity  
A process() 0 3 1
A run() 0 3 1
A __construct() 0 5 1
A discoverSignature() 0 3 2
A getOutput() 0 3 1
A addShortcodesFromArray() 0 7 2
A expandShortcode() 0 5 2
A processInput() 0 7 1
A addShortcode() 0 5 1
A discoverShortcodes() 0 4 1
1
<?php
2
3
namespace Hyde\Framework\Modules\Markdown;
4
5
use Hyde\Framework\Contracts\MarkdownProcessorContract;
6
use Hyde\Framework\Contracts\MarkdownShortcodeContract;
7
use Hyde\Framework\Modules\Markdown\Shortcodes\AbstractColoredBlockquote;
8
9
/**
10
 * Handle shortcode processing for Markdown conversions.
11
 *
12
 * The shortcode system has a few limitations, as it is meant to be simple
13
 * by design so that it is easy to understand how the code works, and
14
 * what each shortcode does. Shortcodes are expanded on a per-line basis,
15
 * and do not support multi-line input. Shortcodes are expected to be
16
 * the very first thing on a line. The signature is a static string
17
 * that is used to identify the shortcode. The built-in shortcodes
18
 * do not use regex, as that would make them harder to read.
19
 *
20
 * @todo Refactor shortcode manager to singleton as it does not need to be re-instantiated
21
 *      for each Markdown conversion.
22
 *
23
 * @see \Hyde\Framework\Testing\Feature\Services\Markdown\ShortcodeProcessorTest
24
 * @phpstan-consistent-constructor
25
 */
26
class ShortcodeProcessor implements MarkdownProcessorContract
27
{
28
    /**
29
     * The input Markdown document body.
30
     */
31
    protected string $input;
32
33
    /**
34
     * The processed Markdown document body.
35
     */
36
    protected string $output;
37
38
    /**
39
     * The activated shortcode instances.
40
     */
41
    public array $shortcodes;
42
43
    public function __construct(string $input)
44
    {
45
        $this->input = $input;
46
47
        $this->discoverShortcodes();
48
    }
49
50
    public function processInput(): static
51
    {
52
        $this->output = implode("\n", array_map(function ($line) {
53
            return $this->expandShortcode($line);
54
        }, explode("\n", $this->input)));
55
56
        return $this;
57
    }
58
59
    public function getOutput(): string
60
    {
61
        return $this->output;
62
    }
63
64
    public function run(): string
65
    {
66
        return $this->processInput()->getOutput();
67
    }
68
69
    public static function process(string $input): string
70
    {
71
        return (new static($input))->run();
72
    }
73
74
    protected function discoverShortcodes(): void
75
    {
76
        $this->addShortcodesFromArray(array_merge(
77
            AbstractColoredBlockquote::get(),
78
        ));
79
    }
80
81
    public function addShortcodesFromArray(array $shortcodes): static
82
    {
83
        foreach ($shortcodes as $shortcode) {
84
            $this->addShortcode($shortcode);
85
        }
86
87
        return $this;
88
    }
89
90
    public function addShortcode(MarkdownShortcodeContract $shortcode): static
91
    {
92
        $this->shortcodes[$shortcode::signature()] = $shortcode;
93
94
        return $this;
95
    }
96
97
    protected function expandShortcode(string $line): string
98
    {
99
        return array_key_exists($signature = $this->discoverSignature($line), $this->shortcodes)
100
            ? $this->shortcodes[$signature]::resolve($line)
101
            : $line;
102
    }
103
104
    protected function discoverSignature(string $line): string
105
    {
106
        return str_contains($line, ' ') ? substr($line, 0, strpos($line, ' ')) : $line;
107
    }
108
}
109