Passed
Push — main ( b205bb...1d3d49 )
by Mark
12:04
created

EmojiParser::parse()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 26
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 14
nc 2
nop 1
dl 0
loc 26
ccs 15
cts 15
cp 1
crap 3
rs 9.7998
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace League\Emoji\Parser;
6
7
use League\Emoji\Dataset\Emoji as DatasetEmoji;
8
use League\Emoji\Environment\EnvironmentInterface;
9
use League\Emoji\Event\DocumentParsedEvent;
10
use League\Emoji\Event\DocumentPreParsedEvent;
11
use League\Emoji\Lexer\EmojiLexer;
12
use League\Emoji\Node\Document;
13
use League\Emoji\Node\Emoji;
14
use League\Emoji\Node\Node;
15
use League\Emoji\Node\Text;
16
17
final class EmojiParser implements EmojiParserInterface
18
{
19
    public const INDICES = [
20
        EmojiLexer::T_EMOTICON    => 'emoticon',
21
        EmojiLexer::T_HTML_ENTITY => 'htmlEntity',
22
        EmojiLexer::T_SHORTCODE   => 'shortcodes',
23
        EmojiLexer::T_UNICODE     => 'unicode',
24
    ];
25
26
    /** @var EnvironmentInterface */
27
    private $environment;
28
29
    /** @var EmojiLexer */
30
    private $lexer;
31
32 645
    public function __construct(EnvironmentInterface $environment, ?EmojiLexer $lexer = null)
33
    {
34 645
        $this->environment = $environment;
35 645
        $this->lexer       = $lexer ?? new EmojiLexer($environment);
36 645
    }
37
38 3
    public function getLexer(): EmojiLexer
39
    {
40 3
        return $this->lexer;
41
    }
42
43 243
    public function parse(string $input): Document
44
    {
45 243
        $preParsedEvent = new DocumentPreParsedEvent(new Document(), $input);
46 243
        $this->environment->dispatch($preParsedEvent);
47
48 243
        $document = $preParsedEvent->getDocument();
49 243
        $input    = $preParsedEvent->getInput();
50
51 243
        $this->lexer->setInput($input);
52 240
        $this->lexer->moveNext();
53
54 240
        while (true) {
55 240
            if (! $this->lexer->lookahead) {
56 240
                break;
57
            }
58
59 237
            $this->lexer->moveNext();
60
61 237
            $node = $this->parseToken();
62
63 237
            $document->appendNode($node);
64
        }
65
66 240
        $this->environment->dispatch(new DocumentParsedEvent($document));
67
68 240
        return $document;
69
    }
70
71 237
    protected function parseToken(): Node
72
    {
73
        /** @var array<string, mixed> $token */
74 237
        $token = $this->lexer->token;
75
76 237
        $value = '';
77 237
        if (((string) $token['value']) !== '') {
78 237
            $value = (string) ($token['value'] ?? '');
79
        }
80
81 237
        $type = (int) $token['type'];
82
83 237
        $node = null;
84 237
        if ($type !== EmojiLexer::T_TEXT && \in_array($type, EmojiLexer::TYPES, true)) {
85 102
            $node = $this->parseEmoji($type, $value);
86
        }
87
88 237
        if ($node === null) {
89 222
            $node = $this->parseText($value);
90
        }
91
92 237
        return $node;
93
    }
94
95 102
    protected function parseEmoji(int $type, string $value): ?Emoji
96
    {
97 102
        $dataset = $this->environment->getRuntimeDataset(self::INDICES[$type]);
98
99
        try {
100
            /** @var DatasetEmoji $emoji */
101 102
            $emoji = $dataset->offsetGet($value);
102
103 99
            return new Emoji($type, $value, $emoji);
104 3
        } catch (\OutOfRangeException $exception) {
105 3
            return null;
106
        }
107
    }
108
109 222
    protected function parseText(string $value): Text
110
    {
111 222
        $text = '';
112 222
        while (true) {
113 222
            $text .= $value;
114 222
            if ($this->lexer->lookahead === null || $this->lexer->lookahead['type'] !== EmojiLexer::T_TEXT) {
115 222
                break;
116
            }
117
118 222
            $value = (string) ($this->lexer->lookahead['value'] ?? '');
119
120 222
            $this->lexer->moveNext();
121
        }
122
123 222
        return new Text($text);
124
    }
125
}
126