Completed
Push — master ( cc20be...6d8ed0 )
by Colin
58:54 queued 23:53
created

LinkParserHelper::manuallyParseLinkDestination()   C

Complexity

Conditions 12
Paths 21

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 12.0082

Importance

Changes 0
Metric Value
dl 0
loc 41
ccs 25
cts 26
cp 0.9615
rs 6.9666
c 0
b 0
f 0
cc 12
nc 21
nop 1
crap 12.0082

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 *
8
 * Original code based on the CommonMark JS reference parser (https://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\Util;
16
17
use League\CommonMark\Cursor;
18
19
final class LinkParserHelper
20
{
21
    /**
22
     * Attempt to parse link destination
23
     *
24
     * @param Cursor $cursor
25
     *
26
     * @return null|string The string, or null if no match
27
     */
28 420
    public static function parseLinkDestination(Cursor $cursor): ?string
29
    {
30 420
        if ($res = $cursor->match(RegexHelper::REGEX_LINK_DESTINATION_BRACES)) {
31
            // Chop off surrounding <..>:
32 30
            return UrlEncoder::unescapeAndEncode(
33 30
                RegexHelper::unescape(\substr($res, 1, -1))
34
            );
35
        }
36
37 393
        if ($cursor->getCharacter() === '<') {
38 9
            return null;
39
        }
40
41 384
        $destination = self::manuallyParseLinkDestination($cursor);
42 384
        if ($destination === null) {
43 3
            return null;
44
        }
45
46 381
        return UrlEncoder::unescapeAndEncode(
47 381
            RegexHelper::unescape($destination)
48
        );
49
    }
50
51
    /**
52
     * @param Cursor $cursor
53
     *
54
     * @return int
55
     */
56 426
    public static function parseLinkLabel(Cursor $cursor): int
57
    {
58 426
        $match = $cursor->match('/^\[(?:[^\\\\\[\]]|\\\\.){0,1000}\]/');
59 426
        if ($match === null) {
60 228
            return 0;
61
        }
62
63 399
        $length = \mb_strlen($match, 'utf-8');
64
65 399
        if ($length > 1001) {
66
            return 0;
67
        }
68
69 399
        return $length;
70
    }
71
72
    /**
73
     * Attempt to parse link title (sans quotes)
74
     *
75
     * @param Cursor $cursor
76
     *
77
     * @return null|string The string, or null if no match
78
     */
79 183
    public static function parseLinkTitle(Cursor $cursor): ?string
80
    {
81 183
        if ($title = $cursor->match('/' . RegexHelper::PARTIAL_LINK_TITLE . '/')) {
82
            // Chop off quotes from title and unescape
83 138
            return RegexHelper::unescape(\substr($title, 1, -1));
84
        }
85
86 45
        return null;
87
    }
88
89
    /**
90
     * @param Cursor $cursor
91
     *
92
     * @return string|null
93
     */
94 384
    private static function manuallyParseLinkDestination(Cursor $cursor): ?string
95
    {
96 384
        $oldPosition = $cursor->getPosition();
97 384
        $oldState = $cursor->saveState();
98
99 384
        $openParens = 0;
100 384
        while (($c = $cursor->getCharacter()) !== null) {
101 381
            if ($c === '\\' && $cursor->peek() !== null && RegexHelper::isEscapable($cursor->peek())) {
102 18
                $cursor->advanceBy(2);
103 381
            } elseif ($c === '(') {
104 12
                $cursor->advanceBy(1);
105 12
                $openParens++;
106 381
            } elseif ($c === ')') {
107 117
                if ($openParens < 1) {
108 114
                    break;
109
                }
110
111 12
                $cursor->advanceBy(1);
112 12
                $openParens--;
113 378
            } elseif (\preg_match(RegexHelper::REGEX_WHITESPACE_CHAR, $c)) {
114 177
                break;
115
            } else {
116 378
                $cursor->advanceBy(1);
117
            }
118
        }
119
120 384
        if ($openParens !== 0) {
121
            return null;
122
        }
123
124 384
        if ($cursor->getPosition() === $oldPosition && $c !== ')') {
125 3
            return null;
126
        }
127
128 381
        $newPos = $cursor->getPosition();
129 381
        $cursor->restoreState($oldState);
130
131 381
        $cursor->advanceBy($newPos - $cursor->getPosition());
132
133 381
        return $cursor->getPreviousText();
134
    }
135
}
136