Skip to content

Commit ed7b791

Browse files
committed
Limit characters after tag name
Previously we allowed all characters after a tag name which made it a bit fuzzy how tags are handled. Psr-5 is more strict about the characters that are allowed in tags and those that are part of the body. A tag name can now be followed by `(`, <space> and `{` all other characters are forbidden. The first character of the body is not restricted anymore. fixes #165
1 parent 6a88d1a commit ed7b791

File tree

2 files changed

+90
-8
lines changed

2 files changed

+90
-8
lines changed

src/DocBlock/StandardTagFactory.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use function get_class;
4747
use function preg_match;
4848
use function strpos;
49+
use function trim;
4950

5051
/**
5152
* Creates a Tag object given the contents of a tag.
@@ -147,13 +148,7 @@ public function create(string $tagLine, ?TypeContext $context = null) : Tag
147148

148149
[$tagName, $tagBody] = $this->extractTagParts($tagLine);
149150

150-
if ($tagBody !== '' && strpos($tagBody, '[') === 0) {
151-
throw new InvalidArgumentException(
152-
'The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'
153-
);
154-
}
155-
156-
return $this->createTag($tagBody, $tagName, $context);
151+
return $this->createTag(trim($tagBody), $tagName, $context);
157152
}
158153

159154
/**
@@ -199,7 +194,7 @@ public function registerTagHandler(string $tagName, string $handler) : void
199194
private function extractTagParts(string $tagLine) : array
200195
{
201196
$matches = [];
202-
if (!preg_match('/^@(' . self::REGEX_TAGNAME . ')(?:\s*([^\s].*)|$)/us', $tagLine, $matches)) {
197+
if (!preg_match('/^@(' . self::REGEX_TAGNAME . ')((?:[\s\(\{:])\s*([^\s].*)|$)/us', $tagLine, $matches)) {
203198
throw new InvalidArgumentException(
204199
'The tag "' . $tagLine . '" does not seem to be wellformed, please check it for errors'
205200
);

tests/unit/DocBlock/StandardTagFactoryTest.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace phpDocumentor\Reflection\DocBlock;
1515

16+
use InvalidArgumentException;
1617
use Mockery as m;
1718
use phpDocumentor\Reflection\DocBlock\Tags\Author;
1819
use phpDocumentor\Reflection\DocBlock\Tags\Formatter;
@@ -341,4 +342,90 @@ public function testInvalidTagIsReturnedOnFailure() : void
341342

342343
$this->assertInstanceOf(InvalidTag::class, $tag);
343344
}
345+
346+
/**
347+
* @dataProvider validTagProvider
348+
*/
349+
public function testValidFormattedTags(string $input, string $tagName, string $render) : void
350+
{
351+
$fqsenResolver = $this->prophesize(FqsenResolver::class);
352+
$tagFactory = new StandardTagFactory($fqsenResolver->reveal());
353+
$tagFactory->registerTagHandler('tag', Generic::class);
354+
$tag = $tagFactory->create($input);
355+
356+
self::assertSame($tagName, $tag->getName());
357+
self::assertSame($render, $tag->render());
358+
}
359+
360+
/**
361+
* @return string[][]
362+
*
363+
* @phpstan-return array<string, array<int, string>>
364+
*/
365+
public function validTagProvider() : array
366+
{
367+
//rendered result is adding a space, because the tags are not rendered properly.
368+
return [
369+
'tag without body' => [
370+
'@tag',
371+
'tag',
372+
'@tag',
373+
],
374+
'tag specialization' => [
375+
'@tag:some-spec',
376+
'tag',
377+
'@tag :some-spec',
378+
],
379+
'tag with textual description' => [
380+
'@tag some text',
381+
'tag',
382+
'@tag some text',
383+
],
384+
'tag [a]' => [
385+
'@tag [is valid]',
386+
'tag',
387+
'@tag [is valid]',
388+
],
389+
'tag {a}' => [
390+
'@tag {is valid}',
391+
'tag',
392+
'@tag {is valid}',
393+
],
394+
'tag{a}' => [
395+
'@tag{is valid}',
396+
'tag',
397+
'@tag {is valid}',
398+
],
399+
'tag(a)' => [
400+
'@tag(is valid)',
401+
'tag',
402+
'@tag (is valid)',
403+
],
404+
];
405+
}
406+
407+
/**
408+
* @dataProvider invalidTagProvider
409+
*/
410+
public function testInValidFormattedTags(string $input) : void
411+
{
412+
$this->expectException(InvalidArgumentException::class);
413+
$fqsenResolver = $this->prophesize(FqsenResolver::class);
414+
$tagFactory = new StandardTagFactory($fqsenResolver->reveal());
415+
$tagFactory->registerTagHandler('tag', Generic::class);
416+
$tagFactory->create($input);
417+
}
418+
419+
/**
420+
* @return string[][]
421+
*
422+
* @phpstan-return list<array<int, string>>
423+
*/
424+
public function invalidTagProvider() : array
425+
{
426+
return [
427+
['@tag[invalid]'],
428+
['@tag@invalid'],
429+
];
430+
}
344431
}

0 commit comments

Comments
 (0)