Completed
Push — master ( d0c235...d2408c )
by Colin
12s
created

QuoteParser::getNormalizedQuoteCharacter()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 3.0416

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
ccs 5
cts 6
cp 0.8333
rs 9.9332
cc 3
nc 3
nop 1
crap 3.0416
1
<?php
2
3
/*
4
 * This file is part of the league/commonmark-ext-smartpunct package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 *
8
 * Original code based on the CommonMark JS reference parser (http://bitly.com/commonmark-js)
9
 *  - (c) John MacFarlane
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace League\CommonMark\Ext\SmartPunct;
16
17
use League\CommonMark\Delimiter\Delimiter;
18
use League\CommonMark\Inline\Parser\InlineParserInterface;
19
use League\CommonMark\InlineParserContext;
20
use League\CommonMark\Util\RegexHelper;
21
22
final class QuoteParser implements InlineParserInterface
23
{
24
    public const DOUBLE_QUOTES = [Quote::DOUBLE_QUOTE, Quote::DOUBLE_QUOTE_OPENER, Quote::DOUBLE_QUOTE_CLOSER];
25
    public const SINGLE_QUOTES = [Quote::SINGLE_QUOTE, Quote::SINGLE_QUOTE_OPENER, Quote::SINGLE_QUOTE_CLOSER];
26
27
    /**
28
     * @return string[]
29
     */
30 45
    public function getCharacters(): array
31
    {
32 45
        return array_merge(self::DOUBLE_QUOTES, self::SINGLE_QUOTES);
33
    }
34
35
    /**
36
     * Normalizes any quote characters found and manually adds them to the delimiter stack
37
     *
38
     * @param InlineParserContext $inlineContext
39
     *
40
     * @return bool
41
     */
42 27
    public function parse(InlineParserContext $inlineContext): bool
43
    {
44 27
        $cursor = $inlineContext->getCursor();
45 27
        $normalizedCharacter = $this->getNormalizedQuoteCharacter($cursor->getCharacter());
46
47 27
        $charBefore = $cursor->peek(-1);
48 27
        if ($charBefore === null) {
49 21
            $charBefore = "\n";
50
        }
51
52 27
        $cursor->advance();
53
54 27
        $charAfter = $cursor->getCharacter();
55 27
        if ($charAfter === null) {
56 15
            $charAfter = "\n";
57
        }
58
59 27
        list($leftFlanking, $rightFlanking) = $this->determineFlanking($charBefore, $charAfter);
60 27
        $canOpen = $leftFlanking && !$rightFlanking;
61 27
        $canClose = $rightFlanking;
62
63 27
        $node = new Quote($normalizedCharacter, ['delim' => true]);
64 27
        $inlineContext->getContainer()->appendChild($node);
65
66
        // Add entry to stack to this opener
67 27
        $inlineContext->getDelimiterStack()->push(new Delimiter($normalizedCharacter, 1, $node, $canOpen, $canClose));
68
69 27
        return true;
70
    }
71
72
    /**
73
     * @param string $character
74
     *
75
     * @return string|null
76
     */
77 27
    private function getNormalizedQuoteCharacter($character)
78
    {
79 27
        if (in_array($character, self::DOUBLE_QUOTES)) {
80 12
            return Quote::DOUBLE_QUOTE;
81 24
        } elseif (in_array($character, self::SINGLE_QUOTES)) {
82 24
            return Quote::SINGLE_QUOTE;
83
        }
84
85
        return $character;
86
    }
87
88
    /**
89
     * @param string $charBefore
90
     * @param string $charAfter
91
     *
92
     * @return string[]
93
     */
94 27
    private function determineFlanking($charBefore, $charAfter)
95
    {
96 27
        $afterIsWhitespace = preg_match('/\pZ|\s/u', $charAfter);
97 27
        $afterIsPunctuation = preg_match(RegexHelper::REGEX_PUNCTUATION, $charAfter);
98 27
        $beforeIsWhitespace = preg_match('/\pZ|\s/u', $charBefore);
99 27
        $beforeIsPunctuation = preg_match(RegexHelper::REGEX_PUNCTUATION, $charBefore);
100
101 27
        $leftFlanking = !$afterIsWhitespace &&
102 27
            !($afterIsPunctuation &&
103 27
                !$beforeIsWhitespace &&
104 27
                !$beforeIsPunctuation);
105
106 27
        $rightFlanking = !$beforeIsWhitespace &&
107 27
            !($beforeIsPunctuation &&
108 27
                !$afterIsWhitespace &&
109 27
                !$afterIsPunctuation);
110
111 27
        return [$leftFlanking, $rightFlanking];
112
    }
113
}
114