mirror of
https://github.com/danog/phpdoc-parser.git
synced 2024-11-30 04:29:20 +01:00
Fixed parsing description started with HTML tag
This commit is contained in:
parent
2b0e830f0b
commit
1948aa842a
@ -12,7 +12,6 @@ class PhpDocParser
|
|||||||
private const DISALLOWED_DESCRIPTION_START_TOKENS = [
|
private const DISALLOWED_DESCRIPTION_START_TOKENS = [
|
||||||
Lexer::TOKEN_UNION,
|
Lexer::TOKEN_UNION,
|
||||||
Lexer::TOKEN_INTERSECTION,
|
Lexer::TOKEN_INTERSECTION,
|
||||||
Lexer::TOKEN_OPEN_ANGLE_BRACKET,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @var TypeParser */
|
/** @var TypeParser */
|
||||||
|
@ -65,6 +65,14 @@ class TypeParser
|
|||||||
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {
|
||||||
$tokens->dropSavePoint(); // because of ConstFetchNode
|
$tokens->dropSavePoint(); // because of ConstFetchNode
|
||||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
|
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {
|
||||||
|
$tokens->pushSavePoint();
|
||||||
|
|
||||||
|
$isHtml = $this->isHtml($tokens);
|
||||||
|
$tokens->rollback();
|
||||||
|
if ($isHtml) {
|
||||||
|
return $type;
|
||||||
|
}
|
||||||
|
|
||||||
$type = $this->parseGeneric($tokens, $type);
|
$type = $this->parseGeneric($tokens, $type);
|
||||||
|
|
||||||
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
if ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {
|
||||||
@ -161,6 +169,35 @@ class TypeParser
|
|||||||
return new Ast\Type\NullableTypeNode($type);
|
return new Ast\Type\NullableTypeNode($type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isHtml(TokenIterator $tokens): bool
|
||||||
|
{
|
||||||
|
$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);
|
||||||
|
|
||||||
|
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$htmlTagName = $tokens->currentTokenValue();
|
||||||
|
|
||||||
|
$tokens->next();
|
||||||
|
|
||||||
|
if (!$tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!$tokens->isCurrentTokenType(Lexer::TOKEN_END)) {
|
||||||
|
if (
|
||||||
|
$tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)
|
||||||
|
&& strpos($tokens->currentTokenValue(), '/' . $htmlTagName . '>') !== false
|
||||||
|
) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tokens->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType): Ast\Type\GenericTypeNode
|
public function parseGeneric(TokenIterator $tokens, Ast\Type\IdentifierTypeNode $baseType): Ast\Type\GenericTypeNode
|
||||||
{
|
{
|
||||||
|
@ -66,6 +66,7 @@ class PhpDocParserTest extends \PHPUnit\Framework\TestCase
|
|||||||
* @dataProvider provideTemplateTagsData
|
* @dataProvider provideTemplateTagsData
|
||||||
* @dataProvider provideExtendsTagsData
|
* @dataProvider provideExtendsTagsData
|
||||||
* @dataProvider provideRealWorldExampleData
|
* @dataProvider provideRealWorldExampleData
|
||||||
|
* @dataProvider provideDescriptionWithOrWithoutHtml
|
||||||
* @param string $label
|
* @param string $label
|
||||||
* @param string $input
|
* @param string $input
|
||||||
* @param PhpDocNode $expectedPhpDocNode
|
* @param PhpDocNode $expectedPhpDocNode
|
||||||
@ -3130,6 +3131,78 @@ chunk. Must be higher that in the previous request.'),
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function provideDescriptionWithOrWithoutHtml(): \Iterator
|
||||||
|
{
|
||||||
|
yield [
|
||||||
|
'Description with HTML tags in @return tag (close tags together)',
|
||||||
|
'/**' . PHP_EOL .
|
||||||
|
' * @return Foo <strong>Important <i>description</i></strong>' . PHP_EOL .
|
||||||
|
' */',
|
||||||
|
new PhpDocNode([
|
||||||
|
new PhpDocTagNode(
|
||||||
|
'@return',
|
||||||
|
new ReturnTagValueNode(
|
||||||
|
new IdentifierTypeNode('Foo'),
|
||||||
|
'<strong>Important <i>description</i></strong>'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'Description with HTML tags in @throws tag (closed tags with text between)',
|
||||||
|
'/**' . PHP_EOL .
|
||||||
|
' * @throws FooException <strong>Important <em>description</em> etc</strong>' . PHP_EOL .
|
||||||
|
' */',
|
||||||
|
new PhpDocNode([
|
||||||
|
new PhpDocTagNode(
|
||||||
|
'@throws',
|
||||||
|
new ThrowsTagValueNode(
|
||||||
|
new IdentifierTypeNode('FooException'),
|
||||||
|
'<strong>Important <em>description</em> etc</strong>'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'Description with HTML tags in @mixin tag',
|
||||||
|
'/**' . PHP_EOL .
|
||||||
|
' * @mixin Mixin <strong>Important description</strong>' . PHP_EOL .
|
||||||
|
' */',
|
||||||
|
new PhpDocNode([
|
||||||
|
new PhpDocTagNode(
|
||||||
|
'@mixin',
|
||||||
|
new MixinTagValueNode(
|
||||||
|
new IdentifierTypeNode('Mixin'),
|
||||||
|
'<strong>Important description</strong>'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
yield [
|
||||||
|
'Description with unclosed HTML tags in @return tag - unclosed HTML tag is parsed as generics',
|
||||||
|
'/**' . PHP_EOL .
|
||||||
|
' * @return Foo <strong>Important description' . PHP_EOL .
|
||||||
|
' */',
|
||||||
|
new PhpDocNode([
|
||||||
|
new PhpDocTagNode(
|
||||||
|
'@return',
|
||||||
|
new ReturnTagValueNode(
|
||||||
|
new GenericTypeNode(
|
||||||
|
new IdentifierTypeNode('Foo'),
|
||||||
|
[
|
||||||
|
new IdentifierTypeNode('strong'),
|
||||||
|
]
|
||||||
|
),
|
||||||
|
'Important description'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function dataParseTagValue(): array
|
public function dataParseTagValue(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
Loading…
Reference in New Issue
Block a user