Skip to content

Commit b451b2f

Browse files
JanTvrdikondrejmirtes
authored andcommittedMar 15, 2021
Preserve whitespace formatting of text nodes
1 parent 2e17e4a commit b451b2f

File tree

3 files changed

+71
-59
lines changed

3 files changed

+71
-59
lines changed
 

Diff for: ‎src/Lexer/Lexer.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,10 +139,10 @@ private function initialize(): void
139139
self::TOKEN_EQUAL => '=',
140140
self::TOKEN_COLON => ':',
141141

142-
self::TOKEN_OPEN_PHPDOC => '/\\*\\*(?=\\s)',
142+
self::TOKEN_OPEN_PHPDOC => '/\\*\\*(?=\\s)\\x20?+',
143143
self::TOKEN_CLOSE_PHPDOC => '\\*/',
144144
self::TOKEN_PHPDOC_TAG => '@[a-z][a-z0-9-]*+',
145-
self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/))?',
145+
self::TOKEN_PHPDOC_EOL => '\\r?+\\n[\\x09\\x20]*+(?:\\*(?!/)\\x20?+)?',
146146

147147
self::TOKEN_FLOAT => '(?:-?[0-9]++\\.[0-9]*+(?:e-?[0-9]++)?)|(?:-?[0-9]*+\\.[0-9]++(?:e-?[0-9]++)?)|(?:-?[0-9]++e-?[0-9]++)',
148148
self::TOKEN_INTEGER => '-?(?:(?:0b[0-1]++)|(?:0o[0-7]++)|(?:0x[0-9a-f]++)|(?:[0-9]++))',

Diff for: ‎src/Parser/PhpDocParser.php

+8-20
Original file line numberDiff line numberDiff line change
@@ -61,39 +61,27 @@ private function parseChild(TokenIterator $tokens): Ast\PhpDoc\PhpDocChildNode
6161
private function parseText(TokenIterator $tokens): Ast\PhpDoc\PhpDocTextNode
6262
{
6363
$text = '';
64-
while (true) {
65-
// If we received a Lexer::TOKEN_PHPDOC_EOL, exit early to prevent
66-
// them from being processed.
67-
$currentTokenType = $tokens->currentTokenType();
68-
if ($currentTokenType === Lexer::TOKEN_PHPDOC_EOL) {
69-
break;
70-
}
71-
$text .= $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END);
72-
$text = rtrim($text, " \t");
7364

74-
// If we joined until TOKEN_PHPDOC_EOL, peak at the next tokens to see
75-
// if we have a multiline string to join.
76-
$currentTokenType = $tokens->currentTokenType();
77-
if ($currentTokenType !== Lexer::TOKEN_PHPDOC_EOL) {
65+
while (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
66+
$text .= $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END);
67+
68+
if (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {
7869
break;
7970
}
8071

81-
// Peek at the next token to determine if it is more text that needs
82-
// to be combined.
8372
$tokens->pushSavePoint();
8473
$tokens->next();
85-
$currentTokenType = $tokens->currentTokenType();
86-
if ($currentTokenType !== Lexer::TOKEN_IDENTIFIER) {
74+
75+
if ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG) || $tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL) || $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC) || $tokens->isCurrentTokenType(Lexer::TOKEN_END)) {
8776
$tokens->rollback();
8877
break;
8978
}
9079

91-
// There's more text on a new line, ensure spacing.
80+
$tokens->dropSavePoint();
9281
$text .= "\n";
9382
}
94-
$text = trim($text, " \t");
9583

96-
return new Ast\PhpDoc\PhpDocTextNode($text);
84+
return new Ast\PhpDoc\PhpDocTextNode(trim($text, " \t"));
9785
}
9886

9987

Diff for: ‎tests/PHPStan/Parser/PhpDocParserTest.php

+61-37
Original file line numberDiff line numberDiff line change
@@ -1242,9 +1242,9 @@ public function provideDeprecatedTagsData(): \Iterator
12421242
new PhpDocTagNode(
12431243
'@deprecated',
12441244
new DeprecatedTagValueNode('in Drupal 8.6.0 and will be removed before Drupal 9.0.0. In
1245-
Drupal 9 there will be no way to set the status and in Drupal 8 this
1246-
ability has been removed because mb_*() functions are supplied using
1247-
Symfony\'s polyfill.')
1245+
Drupal 9 there will be no way to set the status and in Drupal 8 this
1246+
ability has been removed because mb_*() functions are supplied using
1247+
Symfony\'s polyfill.')
12481248
),
12491249
]),
12501250
];
@@ -1271,9 +1271,9 @@ public function provideDeprecatedTagsData(): \Iterator
12711271
new PhpDocTagNode(
12721272
'@deprecated',
12731273
new DeprecatedTagValueNode('in Drupal 8.6.0 and will be removed before Drupal 9.0.0. In
1274-
Drupal 9 there will be no way to set the status and in Drupal 8 this
1275-
ability has been removed because mb_*() functions are supplied using
1276-
Symfony\'s polyfill.')
1274+
Drupal 9 there will be no way to set the status and in Drupal 8 this
1275+
ability has been removed because mb_*() functions are supplied using
1276+
Symfony\'s polyfill.')
12771277
),
12781278
]),
12791279
];
@@ -3122,29 +3122,29 @@ public function provideRealWorldExampleData(): \Iterator
31223122
''
31233123
)
31243124
),
3125-
new PhpDocTextNode('An empty array if there is no schema, or an associative array with the
3126-
following key/value pairs:'),
3127-
new PhpDocTextNode('- columns: An array of Schema API column specifications, keyed by column
3128-
name. The columns need to be a subset of the properties defined in
3129-
propertyDefinitions(). The \'not null\' property is ignored if present,
3130-
as it is determined automatically by the storage controller depending
3131-
on the table layout and the property definitions. It is recommended to
3132-
avoid having the column definitions depend on field settings when
3133-
possible. No assumptions should be made on how storage engines
3134-
internally use the original column name to structure their storage.'),
3135-
new PhpDocTextNode('- unique keys: (optional) An array of Schema API unique key definitions.
3136-
Only columns that appear in the \'columns\' array are allowed.'),
3137-
new PhpDocTextNode('- indexes: (optional) An array of Schema API index definitions. Only
3138-
columns that appear in the \'columns\' array are allowed. Those indexes
3139-
will be used as default indexes. Field definitions can specify
3140-
additional indexes or, at their own risk, modify the default indexes
3141-
specified by the field-type module. Some storage engines might not
3142-
support indexes.'),
3143-
new PhpDocTextNode('- foreign keys: (optional) An array of Schema API foreign key
3144-
definitions. Note, however, that the field data is not necessarily
3145-
stored in SQL. Also, the possible usage is limited, as you cannot
3146-
specify another field as related, only existing SQL tables,
3147-
such as {taxonomy_term_data}.'),
3125+
new PhpDocTextNode("An empty array if there is no schema, or an associative array with the
3126+
following key/value pairs:
3127+
- columns: An array of Schema API column specifications, keyed by column
3128+
name. The columns need to be a subset of the properties defined in
3129+
propertyDefinitions(). The 'not null' property is ignored if present,
3130+
as it is determined automatically by the storage controller depending
3131+
on the table layout and the property definitions. It is recommended to
3132+
avoid having the column definitions depend on field settings when
3133+
possible. No assumptions should be made on how storage engines
3134+
internally use the original column name to structure their storage.
3135+
- unique keys: (optional) An array of Schema API unique key definitions.
3136+
Only columns that appear in the 'columns' array are allowed.
3137+
- indexes: (optional) An array of Schema API index definitions. Only
3138+
columns that appear in the 'columns' array are allowed. Those indexes
3139+
will be used as default indexes. Field definitions can specify
3140+
additional indexes or, at their own risk, modify the default indexes
3141+
specified by the field-type module. Some storage engines might not
3142+
support indexes.
3143+
- foreign keys: (optional) An array of Schema API foreign key
3144+
definitions. Note, however, that the field data is not necessarily
3145+
stored in SQL. Also, the possible usage is limited, as you cannot
3146+
specify another field as related, only existing SQL tables,
3147+
such as {taxonomy_term_data}."),
31483148
]),
31493149
];
31503150

@@ -3172,14 +3172,14 @@ public function provideRealWorldExampleData(): \Iterator
31723172
new PhpDocTextNode('Parses a chunked request and return relevant information.'),
31733173
new PhpDocTextNode(''),
31743174
new PhpDocTextNode('This function must return an array containing the following
3175-
keys and their corresponding values:'),
3176-
new PhpDocTextNode('- last: Wheter this is the last chunk of the uploaded file'),
3177-
new PhpDocTextNode('- uuid: A unique id which distinguishes two uploaded files
3178-
This uuid must stay the same among the task of
3179-
uploading a chunked file.'),
3180-
new PhpDocTextNode('- index: A numerical representation of the currently uploaded
3181-
chunk. Must be higher that in the previous request.'),
3182-
new PhpDocTextNode('- orig: The original file name.'),
3175+
keys and their corresponding values:
3176+
- last: Wheter this is the last chunk of the uploaded file
3177+
- uuid: A unique id which distinguishes two uploaded files
3178+
This uuid must stay the same among the task of
3179+
uploading a chunked file.
3180+
- index: A numerical representation of the currently uploaded
3181+
chunk. Must be higher that in the previous request.
3182+
- orig: The original file name.'),
31833183
new PhpDocTextNode(''),
31843184
new PhpDocTagNode(
31853185
'@param',
@@ -3201,6 +3201,30 @@ public function provideRealWorldExampleData(): \Iterator
32013201
]),
32023202
];
32033203

3204+
yield [
3205+
'Description with indented <code>',
3206+
"/**
3207+
* Finder allows searching through directory trees using iterator.
3208+
*
3209+
* <code>
3210+
* Finder::findFiles('*.php')
3211+
* ->size('> 10kB')
3212+
* ->from('.')
3213+
* ->exclude('temp');
3214+
* </code>
3215+
*/",
3216+
new PhpDocNode([
3217+
new PhpDocTextNode('Finder allows searching through directory trees using iterator.'),
3218+
new PhpDocTextNode(''),
3219+
new PhpDocTextNode("<code>
3220+
Finder::findFiles('*.php')
3221+
->size('> 10kB')
3222+
->from('.')
3223+
->exclude('temp');
3224+
</code>"),
3225+
]),
3226+
];
3227+
32043228
yield [
32053229
'string literals in @return',
32063230
"/** @return 'foo'|'bar' */",

0 commit comments

Comments
 (0)
Please sign in to comment.