-
Notifications
You must be signed in to change notification settings - Fork 159
/
Copy pathValidEnumValueSniff.php
150 lines (128 loc) · 4.74 KB
/
ValidEnumValueSniff.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento2\Sniffs\GraphQL;
use PHP_CodeSniffer\Files\File;
/**
* Detects enum values that are not specified in <kbd>SCREAMING_SNAKE_CASE</kbd>.
*/
class ValidEnumValueSniff extends AbstractGraphQLSniff
{
/**
* @inheritDoc
*/
public function register()
{
return [T_CLASS];
}
/**
* @inheritDoc
*/
public function process(File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
//bail out if we're not inspecting an enum
if ($tokens[$stackPtr]['content'] !== 'enum') {
return;
}
$openingCurlyPointer = $this->getOpeningCurlyBracketPointer($stackPtr, $tokens);
$closingCurlyPointer = $this->getClosingCurlyBracketPointer($stackPtr, $tokens);
//if we could not find the closing curly bracket pointer, we add a warning and terminate
if ($openingCurlyPointer === false || $closingCurlyPointer === false) {
$error = 'Possible parse error: %s missing opening or closing brace';
$data = [$tokens[$stackPtr]['content']];
$phpcsFile->addWarning($error, $stackPtr, 'MissingBrace', $data);
return;
}
$values = $this->getValues($openingCurlyPointer, $closingCurlyPointer, $tokens, $phpcsFile->eolChar);
foreach ($values as $pointer => $value) {
if (!$this->isSnakeCase($value, true)) {
$type = 'Enum value';
$error = '%s "%s" is not in SCREAMING_SNAKE_CASE format';
$data = [
$type,
$value,
];
$phpcsFile->addError($error, $pointer, 'NotScreamingSnakeCase', $data);
$phpcsFile->recordMetric($pointer, 'SCREAMING_SNAKE_CASE enum value', 'no');
} else {
$phpcsFile->recordMetric($pointer, 'SCREAMING_SNAKE_CASE enum value', 'yes');
}
}
return $closingCurlyPointer;
}
/**
* Find the closing curly bracket pointer
*
* Seeks the next available token of type {@link T_CLOSE_CURLY_BRACKET}
* in <var>$tokens</var> and returns its pointer.
*
* @param int $startPointer
* @param array $tokens
* @return bool|int
*/
private function getClosingCurlyBracketPointer($startPointer, array $tokens)
{
return $this->seekToken(T_CLOSE_CURLY_BRACKET, $tokens, $startPointer);
}
/**
* Find the opening curly bracket pointer
*
* Seeks the next available token of type {@link T_OPEN_CURLY_BRACKET}
* in <var>$tokens</var> and returns its pointer.
*
* @param int $startPointer
* @param array $tokens
* @return bool|int
*/
private function getOpeningCurlyBracketPointer($startPointer, array $tokens)
{
return $this->seekToken(T_OPEN_CURLY_BRACKET, $tokens, $startPointer);
}
/**
* Finds all enum values contained in <var>$tokens</var> in range <var>$startPointer</var> to
* <var>$endPointer</var>.
*
* The returned array uses token pointers as keys and value names as values.
*
* @param int $startPointer
* @param int $endPointer
* @param array $tokens
* @param string $eolChar
* @return array<int,string>
*/
private function getValues($startPointer, $endPointer, array $tokens, $eolChar)
{
$valueTokenPointer = null;
$enumValue = '';
$values = [];
$skipTypes = [T_COMMENT, T_WHITESPACE];
for ($i = $startPointer + 1; $i < $endPointer; ++$i) {
if (in_array($tokens[$i]['code'], $skipTypes)) {
//NOP This is a token that we have to skip
continue;
}
//add current tokens content to enum value if we have a string
if ($tokens[$i]['code'] === T_STRING) {
$enumValue .= $tokens[$i]['content'];
//and store the pointer if we have not done it already
if ($valueTokenPointer === null) {
$valueTokenPointer = $i;
}
}
//consume directive if we have found one
if ($tokens[$i]['code'] === T_DOC_COMMENT_TAG) {
$i = $this->seekEndOfDirective($tokens, $i);
}
//if current token has a line break, we have found the end of the value definition
if (strpos($tokens[$i]['content'], $eolChar) !== false) {
$values[$valueTokenPointer] = trim($enumValue);
$enumValue = '';
$valueTokenPointer = null;
}
}
return $values;
}
}