240 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			240 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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,
 | 
						|
        ];
 | 
						|
    }
 | 
						|
}
 |