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