123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- <?php declare(strict_types=1);
- namespace PhpParser;
- class Comment implements \JsonSerializable
- {
- protected $text;
- protected $startLine;
- protected $startFilePos;
- protected $startTokenPos;
- protected $endLine;
- protected $endFilePos;
- protected $endTokenPos;
- /**
- * 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,
- int $endLine = -1, int $endFilePos = -1, int $endTokenPos = -1
- ) {
- $this->text = $text;
- $this->startLine = $startLine;
- $this->startFilePos = $startFilePos;
- $this->startTokenPos = $startTokenPos;
- $this->endLine = $endLine;
- $this->endFilePos = $endFilePos;
- $this->endTokenPos = $endTokenPos;
- }
- /**
- * 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 (or -1 if not available)
- */
- public function getStartLine() : int {
- return $this->startLine;
- }
- /**
- * Gets the file offset the comment started on.
- *
- * @return int File offset (or -1 if not available)
- */
- public function getStartFilePos() : int {
- return $this->startFilePos;
- }
- /**
- * Gets the token offset the comment started on.
- *
- * @return int Token offset (or -1 if not available)
- */
- public function getStartTokenPos() : int {
- return $this->startTokenPos;
- }
- /**
- * Gets the line number the comment ends on.
- *
- * @return int Line number (or -1 if not available)
- */
- public function getEndLine() : int {
- return $this->endLine;
- }
- /**
- * Gets the file offset the comment ends on.
- *
- * @return int File offset (or -1 if not available)
- */
- public function getEndFilePos() : int {
- return $this->endFilePos;
- }
- /**
- * Gets the token offset the comment ends on.
- *
- * @return int Token offset (or -1 if not available)
- */
- public function getEndTokenPos() : int {
- return $this->endTokenPos;
- }
- /**
- * Gets the line number the comment started on.
- *
- * @deprecated Use getStartLine() instead
- *
- * @return int Line number
- */
- public function getLine() : int {
- return $this->startLine;
- }
- /**
- * Gets the file offset the comment started on.
- *
- * @deprecated Use getStartFilePos() instead
- *
- * @return int File offset
- */
- public function getFilePos() : int {
- return $this->startFilePos;
- }
- /**
- * Gets the token offset the comment started on.
- *
- * @deprecated Use getStartTokenPos() instead
- *
- * @return int Token offset
- */
- public function getTokenPos() : int {
- return $this->startTokenPos;
- }
- /**
- * 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,
- // TODO: Rename these to include "start".
- 'line' => $this->startLine,
- 'filePos' => $this->startFilePos,
- 'tokenPos' => $this->startTokenPos,
- 'endLine' => $this->endLine,
- 'endFilePos' => $this->endFilePos,
- 'endTokenPos' => $this->endTokenPos,
- ];
- }
- }
|