Passed
Push — latest ( 9a2102...03f783 )
by Mark
03:04
created

Parser::parseShortcode()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 2
c 0
b 0
f 0
dl 0
loc 7
ccs 3
cts 3
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace UnicornFail\Emoji;
6
7
use UnicornFail\Emoji\Token\AbstractToken;
8
use UnicornFail\Emoji\Token\Emoticon;
9
use UnicornFail\Emoji\Token\HtmlEntity;
10
use UnicornFail\Emoji\Token\Shortcode;
11
use UnicornFail\Emoji\Token\Text;
12
use UnicornFail\Emoji\Token\Unicode;
13
use UnicornFail\Emoji\Util\Normalize;
14
15
class Parser implements ParserInterface
16
{
17
    private const TYPE_METHODS = [
18
        Lexer::T_TEXT => 'parseText',
19
        Lexer::T_EMOTICON => 'parseEmoticon',
20
        Lexer::T_HTML_ENTITY => 'parseHtmlEntity',
21
        Lexer::T_SHORTCODE => 'parseShortcode',
22
        Lexer::T_UNICODE => 'parseUnicode',
23
    ];
24
25
    /** @var Configuration|ConfigurationInterface */
26
    private $configuration;
27
28
    /** @var Dataset */
29
    private $dataset;
30
31
    /** @var Lexer */
32
    private $lexer;
33
34 192
    public function __construct(ConfigurationInterface $configuration, Dataset $dataset, ?Lexer $lexer = null)
35
    {
36 192
        $this->configuration = $configuration;
37 192
        $this->dataset       = $dataset;
38 192
        $this->lexer         = $lexer ?? new Lexer($configuration);
39 192
    }
40
41
    /**
42
     * @return AbstractToken[]
43
     */
44 81
    public function parse(string $input): array
45
    {
46 81
        $this->lexer->setInput($input);
47 81
        $this->lexer->moveNext();
48
49 81
        return $this->parseTokens();
50
    }
51
52
    /**
53
     * @return AbstractToken[]
54
     */
55 81
    protected function parseTokens(): array
56
    {
57 81
        $tokens = [];
58 81
        while (true) {
59 81
            if (! $this->lexer->lookahead) {
60 81
                break;
61
            }
62
63 81
            $this->lexer->moveNext();
64
65 81
            $currentToken = \array_merge([
66
                'type' => Lexer::T_TEXT,
67
                'value' => '',
68 81
            ], $this->lexer->token ?? []);
69
70 81
            $method = self::TYPE_METHODS[$currentToken['type']] ?? null;
71 81
            if ($method && ($token = $this->$method($currentToken['value'])) instanceof AbstractToken) {
72 81
                $tokens[] = $token;
73
            }
74
        }
75
76 81
        return $tokens;
77
    }
78
79 18
    protected function parseEmoticon(string $value): ?Emoticon
80
    {
81 18
        $emoji = $this->dataset->indexBy('emoticon')->offsetGet($value);
82
83
        // Clone the configuration here. This is necessary so it can be passed to tokens,
84
        // which may be rendered at a later time; when the configuration may have changed.
85 18
        return $emoji ? new Emoticon(clone $this->configuration, $value, $emoji) : null;
86
    }
87
88 15
    protected function parseHtmlEntity(string $value): ?HtmlEntity
89
    {
90 15
        $emoji = $this->dataset->indexBy('htmlEntity')->offsetGet($value);
91
92
        // Clone the configuration here. This is necessary so it can be passed to tokens,
93
        // which may be rendered at a later time; when the configuration may have changed.
94 15
        $configuration = clone $this->configuration;
95
96 15
        return $emoji ? new HtmlEntity($configuration, $value, $emoji) : null;
97
    }
98
99 54
    protected function parseShortcode(string $value): ?Shortcode
100
    {
101 54
        $emoji = $this->dataset->indexBy('shortcodes')->offsetGet(\current(Normalize::shortcodes($value)));
102
103
        // Clone the configuration here. This is necessary so it can be passed to tokens,
104
        // which may be rendered at a later time; when the configuration may have changed.
105 54
        return $emoji ? new Shortcode(clone $this->configuration, $value, $emoji) : null;
106
    }
107
108 42
    protected function parseUnicode(string $value): ?Unicode
109
    {
110 42
        $emoji = $this->dataset->indexBy('emoji')->offsetGet($value) ?: $this->dataset->indexBy('text')->offsetGet($value);
111
112
        // Clone the configuration here. This is necessary so it can be passed to tokens,
113
        // which may be rendered at a later time; when the configuration may have changed.
114 42
        return $emoji ? new Unicode(clone $this->configuration, $value, $emoji) : null;
115
    }
116
117 66
    protected function parseText(string $value): ?Text
118
    {
119 66
        $text = '';
120 66
        while (true) {
121 66
            $text .= $value;
122 66
            if ($this->lexer->lookahead === null || $this->lexer->lookahead['type'] !== Lexer::T_TEXT) {
123 66
                break;
124
            }
125
126 66
            $value = $this->lexer->lookahead['value'] ?? '';
127 66
            $this->lexer->moveNext();
128
        }
129
130 66
        return $text ? new Text($text) : null;
131
    }
132
}
133