Completed
Push — master ( deae46...6c5f37 )
by Colin
01:01
created

QuoteParser::determineFlanking()   B

Complexity

Conditions 7
Paths 16

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 14
cts 14
cp 1
rs 8.8333
c 0
b 0
f 0
cc 7
nc 16
nop 2
crap 7
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the league/commonmark package.
7
 *
8
 * (c) Colin O'Dell <[email protected]>
9
 *
10
 * Original code based on the CommonMark JS reference parser (http://bitly.com/commonmark-js)
11
 *  - (c) John MacFarlane
12
 *
13
 * For the full copyright and license information, please view the LICENSE
14
 * file that was distributed with this source code.
15
 */
16
17
namespace League\CommonMark\Extension\SmartPunct;
18
19
use League\CommonMark\Delimiter\Delimiter;
20
use League\CommonMark\Parser\Inline\InlineParserInterface;
21
use League\CommonMark\Parser\InlineParserContext;
22
use League\CommonMark\Util\RegexHelper;
23
24
final class QuoteParser implements InlineParserInterface
25
{
26
    public const DOUBLE_QUOTES = [Quote::DOUBLE_QUOTE, Quote::DOUBLE_QUOTE_OPENER, Quote::DOUBLE_QUOTE_CLOSER];
27
    public const SINGLE_QUOTES = [Quote::SINGLE_QUOTE, Quote::SINGLE_QUOTE_OPENER, Quote::SINGLE_QUOTE_CLOSER];
28
29
    /**
30
     * {@inheritdoc}
31
     */
32 51
    public function getCharacters(): array
33
    {
34 51
        return \array_merge(self::DOUBLE_QUOTES, self::SINGLE_QUOTES);
35
    }
36
37
    /**
38
     * Normalizes any quote characters found and manually adds them to the delimiter stack
39
     */
40 33
    public function parse(InlineParserContext $inlineContext): bool
41
    {
42 33
        $cursor    = $inlineContext->getCursor();
43 33
        $character = $cursor->getCharacter();
44
45 33
        if ($character === null) {
46
            return false;
47
        }
48
49 33
        $normalizedCharacter = $this->getNormalizedQuoteCharacter($character);
50
51 33
        $charBefore = $cursor->peek(-1);
52 33
        if ($charBefore === null) {
53 27
            $charBefore = "\n";
54
        }
55
56 33
        $cursor->advance();
57
58 33
        $charAfter = $cursor->getCharacter();
59 33
        if ($charAfter === null) {
60 21
            $charAfter = "\n";
61
        }
62
63 33
        [$leftFlanking, $rightFlanking] = $this->determineFlanking($charBefore, $charAfter);
0 ignored issues
show
Bug introduced by
The variable $leftFlanking does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $rightFlanking does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
64 33
        $canOpen                        = $leftFlanking && ! $rightFlanking;
65 33
        $canClose                       = $rightFlanking;
66
67 33
        $node = new Quote($normalizedCharacter, ['delim' => true]);
68 33
        $inlineContext->getContainer()->appendChild($node);
69
70
        // Add entry to stack to this opener
71 33
        $inlineContext->getDelimiterStack()->push(new Delimiter($normalizedCharacter, 1, $node, $canOpen, $canClose));
72
73 33
        return true;
74
    }
75
76 33
    private function getNormalizedQuoteCharacter(string $character): string
77
    {
78 33
        if (\in_array($character, self::DOUBLE_QUOTES, true)) {
79 18
            return Quote::DOUBLE_QUOTE;
80
        }
81
82 30
        if (\in_array($character, self::SINGLE_QUOTES, true)) {
83 30
            return Quote::SINGLE_QUOTE;
84
        }
85
86
        return $character;
87
    }
88
89
    /**
90
     * @return bool[]
91
     */
92 33
    private function determineFlanking(string $charBefore, string $charAfter): array
93
    {
94 33
        $afterIsWhitespace   = \preg_match('/\pZ|\s/u', $charAfter);
95 33
        $afterIsPunctuation  = \preg_match(RegexHelper::REGEX_PUNCTUATION, $charAfter);
96 33
        $beforeIsWhitespace  = \preg_match('/\pZ|\s/u', $charBefore);
97 33
        $beforeIsPunctuation = \preg_match(RegexHelper::REGEX_PUNCTUATION, $charBefore);
98
99 33
        $leftFlanking = ! $afterIsWhitespace &&
100 33
            ! ($afterIsPunctuation &&
101 33
                ! $beforeIsWhitespace &&
102 33
                ! $beforeIsPunctuation);
103
104 33
        $rightFlanking = ! $beforeIsWhitespace &&
105 33
            ! ($beforeIsPunctuation &&
106 33
                ! $afterIsWhitespace &&
107 33
                ! $afterIsPunctuation);
108
109 33
        return [$leftFlanking, $rightFlanking];
110
    }
111
}
112