phpstan/phpdoc-parser

No way to know what the annotation name was

williamdes opened this issue · 3 comments

This is my second attempt to use this lib, after copy pasting some lines from your unit tests I was able to start using this lib.

I am trying to replace phpdocumentor lib by yours in Doctum. (why: I still do not know, but I hope to have better type parsing with your lib)

My problem is that I need to build the method description and long description. But this lib does not give me a way to exclude non pure text nodes from the ones that are like @{something} {text}.

This gives more output that I would need to build a long method description.

Here is my function, ``getLongDescriptionFromNodes` would need to know if there was a tag on the line

    public function parse(?string $comment, ParserContext $context): DocBlockNode
    {
        /** @var PhpDocNode|null */
        $docBlock     = null;
        $errorMessage = '';
        $result       = new DocBlockNode();

        if ($comment === null) {
            return $result;
        }

        try {
	    $lexer = new Lexer();
            $constExprParser = new ConstExprParser();
            $phpDocParser = new PhpDocParser(new TypeParser($constExprParser), $constExprParser);
            $tokens = new TokenIterator($lexer->tokenize($comment));
            $docBlock = $phpDocParser->parse($tokens);
        } catch (\Exception $e) {
            $errorMessage = $e->getMessage();
        }

        if ($errorMessage) {
            $result->addError($errorMessage);

            return $result;
        }

        $textNodes = $this->getTextNodes($docBlock);
        /** @var PhpDocTextNode|null $firstTextNode */
        $firstTextNode = array_shift($textNodes);
        // First found and not empty test
        if ($firstTextNode !== null && $firstTextNode->text !== '') {
            $result->setShortDesc($firstTextNode->text);
        }
        $longDescription = $this->getLongDescriptionFromNodes($textNodes);
        if ($longDescription !== null) {
            $result->setLongDesc($longDescription);
        }

        foreach ($docBlock->getTags() as $tag) {
            $result->addTag($tag->name, $this->parseTag($tag));
        }

        return $result;
    }

	/**
	 * @param PhpDocTextNode[] $nodes
	 */
    public function getLongDescriptionFromNodes(array $nodes): ?string
    {
        $contents = '';
        foreach ($nodes as $textNode) {
            $contents .= $textNode->text;
        }

        $contents = trim($contents, ' ');

        return $contents === '' ? null : $contents;
    }

	/**
	 * @return PhpDocTextNode[]
	 */
	public function getTextNodes(PhpDocNode $node): array
	{
		return array_filter($node->children, static function (PhpDocChildNode $child): bool {
			return $child instanceof PhpDocTextNode;
		});
    }

And code in a class

    /**
     * Return a copy of this list which contains items matching any of these characteristics.
     *
     * See {@link filter()}
     * @example // only bob in the list
     *          $list = $list->filterAny('Name', 'bob');
     *          // SQL: WHERE "Name" = 'bob'
     * @example // azis or bob in the list
     *          $list = $list->filterAny('Name', array('aziz', 'bob');
     *          // SQL: WHERE ("Name" IN ('aziz','bob'))
     * @example // bob or anyone aged 21 in the list
     *          $list = $list->filterAny(array('Name'=>'bob, 'Age'=>21));
     *          // SQL: WHERE ("Name" = 'bob' OR "Age" = '21')
     * @example // bob or anyone aged 21 or 43 in the list
     *          $list = $list->filterAny(array('Name'=>'bob, 'Age'=>array(21, 43)));
     *          // SQL: WHERE ("Name" = 'bob' OR ("Age" IN ('21', '43'))
     * @example // all bobs, phils or anyone aged 21 or 43 in the list
     *          $list = $list->filterAny(array('Name'=>array('bob','phil'), 'Age'=>array(21, 43)));
     *          // SQL: WHERE (("Name" IN ('bob', 'phil')) OR ("Age" IN ('21', '43'))
     *
     * @see Foo
     *
     * @return Foo
     * @throws \Exception
     */
    public function zzd()
    {
        return [];
    }

I don't understand the problem. You can extract the long description like this

function extractDescription(PhpDocNode $node): string
{
    $lines = [];
    foreach ($node->children as $child) {
	    if ($child instanceof PhpDocTextNode) {
		    $lines[] = $child->text;
    
	    } else {
		    break;
	    }
    }
    
    return trim(implode("\n", $lines));
}

I don't understand the problem. You can extract the long description like this

Thank you for the example, but it you try the example doc block I gave above @example lines are included, I need them to not be PhpDocTextNodes or I will not be able to build a proper description

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.