VersionParser::canParse()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 9
ccs 6
cts 6
cp 1
rs 9.6666
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 1
crap 3
1
<?php
2
3
/**
4
 * @copyright   (c) 2014-2017 brian ridley
5
 * @author      brian ridley <[email protected]>
6
 * @license     http://opensource.org/licenses/MIT MIT
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ptlis\SemanticVersion\Parse;
13
14
use ptlis\SemanticVersion\Version\Label\LabelBuilder;
15
use ptlis\SemanticVersion\Version\Version;
16
use ptlis\SemanticVersion\Version\VersionInterface;
17
18
/**
19
 * Matcher that can be used to parse version numbers.
20
 */
21
final class VersionParser
22
{
23
    /** @var LabelBuilder */
24
    private $labelBuilder;
25
26
    /** Array of token patterns that can be used to construct a valid semantic version number */
27
    private $validPatterns = [
28
        [Token::DIGITS],
29
        [Token::DIGITS, Token::DOT_SEPARATOR], // Allow trailing dot
30
        [Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS],
31
        [Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS, Token::DOT_SEPARATOR], // Allow trailing dot
32
        [Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS],
33
        [Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS,
34
            Token::DASH_SEPARATOR, Token::LABEL_STRING],
35
        [Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS, Token::DOT_SEPARATOR, Token::DIGITS,
36
            Token::DASH_SEPARATOR, Token::LABEL_STRING, Token::DOT_SEPARATOR, Token::DIGITS]
37
    ];
38
39
40
    /**
41
     * @param LabelBuilder $labelBuilder
42
     */
43 8
    public function __construct(
44
        LabelBuilder $labelBuilder
45
    ) {
46 8
        $this->labelBuilder = $labelBuilder;
47 8
    }
48
49
    /**
50
     * {@inheritdoc}
51
     */
52 8
    public function canParse(array $tokenList)
53
    {
54 8
        $isVersion = false;
55 8
        foreach ($this->validPatterns as $pattern) {
56 8
            $isVersion = $isVersion || $this->tokensMatchPattern($tokenList, $pattern);
57 8
        }
58
59 8
        return $isVersion;
60
    }
61
62
63
    /**
64
     * Parses the token list into an appropriate value type.
65
     *
66
     * @throws \RuntimeException If the version cannot be parsed.
67
     *
68
     * @param Token[] $tokenList
69
     *
70
     * @return VersionInterface
71
     */
72 8
    public function parse(array $tokenList)
73
    {
74 8
        if (!$this->canParse($tokenList)) {
75 1
            throw new \RuntimeException('Invalid version');
76
        }
77
78 7
        $major = $tokenList[0]->getValue();
79 7
        $minor = 0;
80 7
        $patch = 0;
81 7
        $label = null;
82
83 7
        if (count($tokenList) >= 3) {
84 5
            $minor = $tokenList[2]->getValue();
85 5
        }
86
87 7
        if (count($tokenList) >= 5) {
88 3
            $patch = $tokenList[4]->getValue();
89 3
        }
90
91
        // Build label from tokens following hyphen seperator
92 7
        if (count($tokenList) >= 7) {
93 2
            $label = $this->labelBuilder->buildFromTokens(array_slice($tokenList, 6));
94 2
        }
95
96 7
        return new Version($major, $minor, $patch, $label);
97
    }
98
99
    /**
100
     * Returns true if the tokens match the specified pattern.
101
     *
102
     * @param Token[] $tokenList
103
     * @param string[] $pattern
104
     *
105
     * @return bool
106
     */
107 8
    private function tokensMatchPattern(
108
        array $tokenList,
109
        array $pattern
110
    ) {
111 8
        $matches = count($tokenList) === count($pattern);
112
113 8
        foreach ($tokenList as $index => $token) {
114 8
            if ($matches) {
115 8
                $matches = $pattern[$index] === $token->getType();
116 8
            }
117 8
        }
118
119 8
        return $matches;
120
    }
121
}
122