Passed
Pull Request — master (#2)
by Maxim
02:29
created

CommentLexer::getClassData()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 23
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 4
nop 0
dl 0
loc 23
ccs 17
cts 17
cp 1
crap 6
rs 8.5906
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is a part of "Axessors" library.
4
 *
5
 * @author <[email protected]>
6
 * @license GPL
7
 */
8
9
namespace NoOne4rever\Axessors;
10
11
/**
12
 * Class CommentLexer.
13
 *
14
 * Splits Axessors comment into array of possible tokens.
15
 *
16
 * @package NoOne4rever\Axessors
17
 */
18
class CommentLexer extends Lexer
19
{
20
    private const AXS_COMMENT = '/^#:/';
21
    private const ACCESS_MODIFIER = '/^(\+|~|-)/';
22
    private const KEYWORD = '/^(accessible|writable|readable|axs|wrt|rdb)/';
23
    private const TYPE = '/^((((\\\\)?[a-zA-Z_][a-zA-Z\d_]*(\\\\[a-zA-Z_][a-zA-Z\d_]*)*)(\[(?1)\])?)(\|(?2))*)/';
24
    private const HANDLERS = '/^((?(1),\s*)([a-zA-Z_][a-zA-Z0-9_]*|`([^`]|\\\\`)+((?<!\\\\)`)))+/';
25
    private const CONDITIONS = '/^((?(1)\s*(&&|\|\|)\s*)(\d+(,\d+)?\.\.\d+(,\d+)?|((<|>|!|=)=|%|<|>)\s+\d+(,\d+)?|`([^`]|\\\\`)+((?<!\\\\)`)))+/';
26
    private const HANDLERS_SIGN = '/^->/';
27
    private const ALIAS_SIGN = '/^=>/';
28
    private const ALIAS = '/^[a-zA-Z_][a-zA-Z0-9_]*/';
29
30
    private const TOKEN_LIST = [
31
        self::AXS_COMMENT,
32
        self::ACCESS_MODIFIER,
33
        self::KEYWORD,
34
        self::TYPE,
35
        self::CONDITIONS,
36
        self::HANDLERS_SIGN,
37
        self::HANDLERS,
38
        self::ACCESS_MODIFIER,
39
        self::KEYWORD,
40
        self::CONDITIONS,
41
        self::HANDLERS_SIGN,
42
        self::HANDLERS,
43
        self::ALIAS_SIGN,
44
        self::ALIAS
45
    ];
46
    private const REQUIRED_TOKENS = [0, 1, 2];
47
48
    private const AXS_COMMENT_TOKEN = '#:';
49
50
    /**
51
     * Returns class' data with Axessors properties.
52
     *
53
     * @return ClassData class' data
54
     */
55 5
    public function getClassData(): ClassData
56
    {
57 5
        $classData = new ClassData($this->reflection);
58 5
        for ($i = $this->startLine; $this->isLineEmpty() && $i <= $this->endLine; ++$i) {
59 5
            $this->readLine();
60 5
            if (!$this->isAxsPropertyDef()) {
61 5
                continue;
62
            }
63 5
            $injProcessor = new InjectedStringSuit($this->getAxsComment());
64 5
            $code = $injProcessor->addSlashes('\\');
65 5
            $properties = $this->getProperties();
66 5
            if (count($properties) == 1) {
67 5
                $tokenList = self::TOKEN_LIST;
68
            } else {
69 2
                $tokenList = array_slice(self::TOKEN_LIST, 0, count(self::TOKEN_LIST) - 2);
70
            }
71 5
            $tokens = $this->parse($code, $tokenList, self::REQUIRED_TOKENS);
72 5
            foreach ($this->getProperties() as $propertyName) {
73 5
                $propertyData = new PropertyData($this->reflection->getProperty($propertyName), $tokens);
74 2
                $classData->addProperty($propertyName, $propertyData);
75
            }
76
        }
77 2
        return $classData;
78
    }
79
80
    /**
81
     * Extracts Axessors comment from the code.
82
     *
83
     * @return string Axessors comment
84
     */
85 5
    private function getAxsComment(): string
86
    {
87 5
        return substr($this->currentLine, strpos($this->currentLine, self::AXS_COMMENT_TOKEN));
88
    }
89
90
    /**
91
     * Extracts property name from the code.
92
     *
93
     * @return string[] property name
94
     */
95 5
    private function getProperties(): array
96
    {
97 5
        $line = substr($this->currentLine, 0, strpos($this->currentLine, self::AXS_COMMENT_TOKEN));
98 5
        preg_match_all('/(?<=\$)[a-z_][a-z\d_]*/i', $line, $properties);
99 5
        return $properties[0];
100
    }
101
102
    /**
103
     * Checks if the code given is Axessors property definition.
104
     *
105
     * @return bool result of the checkout
106
     */
107 5
    private function isAxsPropertyDef(): bool
108
    {
109 5
        return (bool)preg_match('/\s*(public|protected|private)(\s*static)?\s+((?(3),)\s*\$[a-z_][a-z\d_]*)+.*?;\s*#:.+/i',
110 5
            $this->currentLine);
111
    }
112
}
113