Comment.php
5.43 KB
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
<?php declare(strict_types=1);
namespace PhpParser;
class Comment implements \JsonSerializable
{
protected $text;
protected $line;
protected $filePos;
protected $tokenPos;
/**
* Constructs a comment node.
*
* @param string $text Comment text (including comment delimiters like /*)
* @param int $startLine Line number the comment started on
* @param int $startFilePos File offset the comment started on
* @param int $startTokenPos Token offset the comment started on
*/
public function __construct(
string $text, int $startLine = -1, int $startFilePos = -1, int $startTokenPos = -1
) {
$this->text = $text;
$this->line = $startLine;
$this->filePos = $startFilePos;
$this->tokenPos = $startTokenPos;
}
/**
* Gets the comment text.
*
* @return string The comment text (including comment delimiters like /*)
*/
public function getText() : string {
return $this->text;
}
/**
* Gets the line number the comment started on.
*
* @return int Line number
*/
public function getLine() : int {
return $this->line;
}
/**
* Gets the file offset the comment started on.
*
* @return int File offset
*/
public function getFilePos() : int {
return $this->filePos;
}
/**
* Gets the token offset the comment started on.
*
* @return int Token offset
*/
public function getTokenPos() : int {
return $this->tokenPos;
}
/**
* Gets the comment text.
*
* @return string The comment text (including comment delimiters like /*)
*/
public function __toString() : string {
return $this->text;
}
/**
* Gets the reformatted comment text.
*
* "Reformatted" here means that we try to clean up the whitespace at the
* starts of the lines. This is necessary because we receive the comments
* without trailing whitespace on the first line, but with trailing whitespace
* on all subsequent lines.
*
* @return mixed|string
*/
public function getReformattedText() {
$text = trim($this->text);
$newlinePos = strpos($text, "\n");
if (false === $newlinePos) {
// Single line comments don't need further processing
return $text;
} elseif (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $text)) {
// Multi line comment of the type
//
// /*
// * Some text.
// * Some more text.
// */
//
// is handled by replacing the whitespace sequences before the * by a single space
return preg_replace('(^\s+\*)m', ' *', $this->text);
} elseif (preg_match('(^/\*\*?\s*[\r\n])', $text) && preg_match('(\n(\s*)\*/$)', $text, $matches)) {
// Multi line comment of the type
//
// /*
// Some text.
// Some more text.
// */
//
// is handled by removing the whitespace sequence on the line before the closing
// */ on all lines. So if the last line is " */", then " " is removed at the
// start of all lines.
return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text);
} elseif (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) {
// Multi line comment of the type
//
// /* Some text.
// Some more text.
// Indented text.
// Even more text. */
//
// is handled by removing the difference between the shortest whitespace prefix on all
// lines and the length of the "/* " opening sequence.
$prefixLen = $this->getShortestWhitespacePrefixLen(substr($text, $newlinePos + 1));
$removeLen = $prefixLen - strlen($matches[0]);
return preg_replace('(^\s{' . $removeLen . '})m', '', $text);
}
// No idea how to format this comment, so simply return as is
return $text;
}
/**
* Get length of shortest whitespace prefix (at the start of a line).
*
* If there is a line with no prefix whitespace, 0 is a valid return value.
*
* @param string $str String to check
* @return int Length in characters. Tabs count as single characters.
*/
private function getShortestWhitespacePrefixLen(string $str) : int {
$lines = explode("\n", $str);
$shortestPrefixLen = \INF;
foreach ($lines as $line) {
preg_match('(^\s*)', $line, $matches);
$prefixLen = strlen($matches[0]);
if ($prefixLen < $shortestPrefixLen) {
$shortestPrefixLen = $prefixLen;
}
}
return $shortestPrefixLen;
}
/**
* @return array
* @psalm-return array{nodeType:string, text:mixed, line:mixed, filePos:mixed}
*/
public function jsonSerialize() : array {
// Technically not a node, but we make it look like one anyway
$type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment';
return [
'nodeType' => $type,
'text' => $this->text,
'line' => $this->line,
'filePos' => $this->filePos,
'tokenPos' => $this->tokenPos,
];
}
}