Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace PhpParser;
|
Chris@0
|
4
|
Chris@0
|
5 class Comment implements \JsonSerializable
|
Chris@0
|
6 {
|
Chris@0
|
7 protected $text;
|
Chris@0
|
8 protected $line;
|
Chris@0
|
9 protected $filePos;
|
Chris@0
|
10
|
Chris@0
|
11 /**
|
Chris@0
|
12 * Constructs a comment node.
|
Chris@0
|
13 *
|
Chris@0
|
14 * @param string $text Comment text (including comment delimiters like /*)
|
Chris@0
|
15 * @param int $startLine Line number the comment started on
|
Chris@0
|
16 * @param int $startFilePos File offset the comment started on
|
Chris@0
|
17 */
|
Chris@0
|
18 public function __construct($text, $startLine = -1, $startFilePos = -1) {
|
Chris@0
|
19 $this->text = $text;
|
Chris@0
|
20 $this->line = $startLine;
|
Chris@0
|
21 $this->filePos = $startFilePos;
|
Chris@0
|
22 }
|
Chris@0
|
23
|
Chris@0
|
24 /**
|
Chris@0
|
25 * Gets the comment text.
|
Chris@0
|
26 *
|
Chris@0
|
27 * @return string The comment text (including comment delimiters like /*)
|
Chris@0
|
28 */
|
Chris@0
|
29 public function getText() {
|
Chris@0
|
30 return $this->text;
|
Chris@0
|
31 }
|
Chris@0
|
32
|
Chris@0
|
33 /**
|
Chris@0
|
34 * Gets the line number the comment started on.
|
Chris@0
|
35 *
|
Chris@0
|
36 * @return int Line number
|
Chris@0
|
37 */
|
Chris@0
|
38 public function getLine() {
|
Chris@0
|
39 return $this->line;
|
Chris@0
|
40 }
|
Chris@0
|
41
|
Chris@0
|
42 /**
|
Chris@0
|
43 * Gets the file offset the comment started on.
|
Chris@0
|
44 *
|
Chris@0
|
45 * @return int File offset
|
Chris@0
|
46 */
|
Chris@0
|
47 public function getFilePos() {
|
Chris@0
|
48 return $this->filePos;
|
Chris@0
|
49 }
|
Chris@0
|
50
|
Chris@0
|
51 /**
|
Chris@0
|
52 * Gets the comment text.
|
Chris@0
|
53 *
|
Chris@0
|
54 * @return string The comment text (including comment delimiters like /*)
|
Chris@0
|
55 */
|
Chris@0
|
56 public function __toString() {
|
Chris@0
|
57 return $this->text;
|
Chris@0
|
58 }
|
Chris@0
|
59
|
Chris@0
|
60 /**
|
Chris@0
|
61 * Gets the reformatted comment text.
|
Chris@0
|
62 *
|
Chris@0
|
63 * "Reformatted" here means that we try to clean up the whitespace at the
|
Chris@0
|
64 * starts of the lines. This is necessary because we receive the comments
|
Chris@0
|
65 * without trailing whitespace on the first line, but with trailing whitespace
|
Chris@0
|
66 * on all subsequent lines.
|
Chris@0
|
67 *
|
Chris@0
|
68 * @return mixed|string
|
Chris@0
|
69 */
|
Chris@0
|
70 public function getReformattedText() {
|
Chris@0
|
71 $text = trim($this->text);
|
Chris@0
|
72 $newlinePos = strpos($text, "\n");
|
Chris@0
|
73 if (false === $newlinePos) {
|
Chris@0
|
74 // Single line comments don't need further processing
|
Chris@0
|
75 return $text;
|
Chris@0
|
76 } elseif (preg_match('((*BSR_ANYCRLF)(*ANYCRLF)^.*(?:\R\s+\*.*)+$)', $text)) {
|
Chris@0
|
77 // Multi line comment of the type
|
Chris@0
|
78 //
|
Chris@0
|
79 // /*
|
Chris@0
|
80 // * Some text.
|
Chris@0
|
81 // * Some more text.
|
Chris@0
|
82 // */
|
Chris@0
|
83 //
|
Chris@0
|
84 // is handled by replacing the whitespace sequences before the * by a single space
|
Chris@0
|
85 return preg_replace('(^\s+\*)m', ' *', $this->text);
|
Chris@0
|
86 } elseif (preg_match('(^/\*\*?\s*[\r\n])', $text) && preg_match('(\n(\s*)\*/$)', $text, $matches)) {
|
Chris@0
|
87 // Multi line comment of the type
|
Chris@0
|
88 //
|
Chris@0
|
89 // /*
|
Chris@0
|
90 // Some text.
|
Chris@0
|
91 // Some more text.
|
Chris@0
|
92 // */
|
Chris@0
|
93 //
|
Chris@0
|
94 // is handled by removing the whitespace sequence on the line before the closing
|
Chris@0
|
95 // */ on all lines. So if the last line is " */", then " " is removed at the
|
Chris@0
|
96 // start of all lines.
|
Chris@0
|
97 return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text);
|
Chris@0
|
98 } elseif (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) {
|
Chris@0
|
99 // Multi line comment of the type
|
Chris@0
|
100 //
|
Chris@0
|
101 // /* Some text.
|
Chris@0
|
102 // Some more text.
|
Chris@0
|
103 // Indented text.
|
Chris@0
|
104 // Even more text. */
|
Chris@0
|
105 //
|
Chris@0
|
106 // is handled by removing the difference between the shortest whitespace prefix on all
|
Chris@0
|
107 // lines and the length of the "/* " opening sequence.
|
Chris@0
|
108 $prefixLen = $this->getShortestWhitespacePrefixLen(substr($text, $newlinePos + 1));
|
Chris@0
|
109 $removeLen = $prefixLen - strlen($matches[0]);
|
Chris@0
|
110 return preg_replace('(^\s{' . $removeLen . '})m', '', $text);
|
Chris@0
|
111 }
|
Chris@0
|
112
|
Chris@0
|
113 // No idea how to format this comment, so simply return as is
|
Chris@0
|
114 return $text;
|
Chris@0
|
115 }
|
Chris@0
|
116
|
Chris@0
|
117 private function getShortestWhitespacePrefixLen($str) {
|
Chris@0
|
118 $lines = explode("\n", $str);
|
Chris@0
|
119 $shortestPrefixLen = INF;
|
Chris@0
|
120 foreach ($lines as $line) {
|
Chris@0
|
121 preg_match('(^\s*)', $line, $matches);
|
Chris@0
|
122 $prefixLen = strlen($matches[0]);
|
Chris@0
|
123 if ($prefixLen < $shortestPrefixLen) {
|
Chris@0
|
124 $shortestPrefixLen = $prefixLen;
|
Chris@0
|
125 }
|
Chris@0
|
126 }
|
Chris@0
|
127 return $shortestPrefixLen;
|
Chris@0
|
128 }
|
Chris@0
|
129
|
Chris@0
|
130 public function jsonSerialize() {
|
Chris@0
|
131 // Technically not a node, but we make it look like one anyway
|
Chris@0
|
132 $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment';
|
Chris@0
|
133 return [
|
Chris@0
|
134 'nodeType' => $type,
|
Chris@0
|
135 'text' => $this->text,
|
Chris@0
|
136 'line' => $this->line,
|
Chris@0
|
137 'filePos' => $this->filePos,
|
Chris@0
|
138 ];
|
Chris@0
|
139 }
|
Chris@0
|
140 } |