Skip to content

Commit 00d2f96

Browse files
author
smoench
committed
refactor php compactor
1 parent 6c6f139 commit 00d2f96

12 files changed

Lines changed: 1031 additions & 452 deletions

File tree

src/Annotation/CompactedFormatter.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
2323
use function strpos;
2424

25+
/**
26+
* @private
27+
*/
2528
final class CompactedFormatter implements Formatter
2629
{
2730
public function format(Tag $tag): string
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the box project.
7+
*
8+
* (c) Kevin Herrera <kevin@herrera.io>
9+
* Théo Fidry <theo.fidry@gmail.com>
10+
*
11+
* This source file is subject to the MIT license that is bundled
12+
* with this source code in the file LICENSE.
13+
*/
14+
15+
namespace KevinGH\Box\Annotation;
16+
17+
use function count;
18+
use function str_repeat;
19+
use function substr_count;
20+
21+
/**
22+
* @private
23+
*/
24+
final class DocblockCompactor
25+
{
26+
private $annotationParser;
27+
28+
public function __construct(DocblockAnnotationParser $annotationParser)
29+
{
30+
$this->annotationParser = $annotationParser;
31+
}
32+
33+
public function compact(string $docblock): string
34+
{
35+
if (false === strpos($docblock, '@')) {
36+
return str_repeat("\n", substr_count($docblock, "\n"));
37+
}
38+
39+
$breaksNbr = substr_count($docblock, "\n");
40+
41+
$annotations = $this->annotationParser->parse($docblock);
42+
43+
if ([] === $annotations) {
44+
return str_repeat("\n", $breaksNbr);
45+
}
46+
47+
$compactedDocblock = '/**';
48+
49+
foreach ($annotations as $annotation) {
50+
$compactedDocblock .= "\n".$annotation;
51+
}
52+
53+
$breaksNbr -= count($annotations);
54+
55+
if ($breaksNbr > 0) {
56+
$compactedDocblock .= str_repeat("\n", $breaksNbr - 1);
57+
$compactedDocblock .= "\n*/";
58+
} else {
59+
// A space is required here to avoid having /***/
60+
$compactedDocblock .= ' */';
61+
}
62+
63+
return $compactedDocblock;
64+
}
65+
}

src/Compactor/Php.php

Lines changed: 5 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -14,117 +14,27 @@
1414

1515
namespace KevinGH\Box\Compactor;
1616

17-
use function count;
18-
use function in_array;
19-
use function is_string;
20-
use KevinGH\Box\Annotation\DocblockAnnotationParser;
21-
use KevinGH\Box\Annotation\InvalidToken;
22-
use function preg_replace;
23-
use RuntimeException;
24-
use function str_repeat;
25-
use function strpos;
26-
use function substr_count;
27-
use const T_COMMENT;
28-
use const T_DOC_COMMENT;
29-
use const T_WHITESPACE;
30-
use function token_get_all;
17+
use KevinGH\Box\Compactor\Php\PhpVersionCompactor;
3118

3219
/**
33-
* A PHP source code compactor copied from Composer.
34-
*
35-
* @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
36-
*
37-
* @author Kevin Herrera <kevin@herrera.io>
38-
* @author Fabien Potencier <fabien@symfony.com>
39-
* @author Jordi Boggiano <j.boggiano@seld.be>
40-
* @author Théo Fidry <theo.fidry@gmail.com>
4120
* @private
4221
*/
4322
final class Php extends FileExtensionCompactor
4423
{
45-
private $annotationParser;
24+
private $phpVersionCompactor;
4625

4726
/**
4827
* {@inheritdoc}
4928
*/
50-
public function __construct(DocblockAnnotationParser $annotationParser, array $extensions = ['php'])
29+
public function __construct(PhpVersionCompactor $phpVersionCompactor, array $extensions = ['php'])
5130
{
5231
parent::__construct($extensions);
5332

54-
$this->annotationParser = $annotationParser;
33+
$this->phpVersionCompactor = $phpVersionCompactor;
5534
}
5635

57-
/**
58-
* {@inheritdoc}
59-
*/
6036
protected function compactContent(string $contents): string
6137
{
62-
$output = '';
63-
64-
foreach (token_get_all($contents) as $token) {
65-
if (is_string($token)) {
66-
$output .= $token;
67-
} elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
68-
if (false !== strpos($token[1], '@')) {
69-
try {
70-
$output .= $this->compactAnnotations($token[1]);
71-
} catch (InvalidToken $exception) {
72-
// This exception is due to the dumper to be out of sync with the current grammar and/or the
73-
// grammar being incomplete. In both cases throwing here is better in order to identify and
74-
// this those cases instead of silently failing.
75-
76-
throw $exception;
77-
} catch (RuntimeException $exception) {
78-
$output .= $token[1];
79-
}
80-
} else {
81-
$output .= str_repeat("\n", substr_count($token[1], "\n"));
82-
}
83-
} elseif (T_WHITESPACE === $token[0]) {
84-
// reduce wide spaces
85-
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
86-
87-
// normalize newlines to \n
88-
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
89-
90-
// trim leading spaces
91-
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
92-
93-
$output .= $whitespace;
94-
} else {
95-
$output .= $token[1];
96-
}
97-
}
98-
99-
return $output;
100-
}
101-
102-
private function compactAnnotations(string $docblock): string
103-
{
104-
$breaksNbr = substr_count($docblock, "\n");
105-
106-
$annotations = $this->annotationParser->parse($docblock);
107-
108-
if ([] === $annotations) {
109-
return str_repeat("\n", $breaksNbr);
110-
}
111-
112-
$compactedDocblock = '/**';
113-
114-
foreach ($annotations as $annotation) {
115-
$compactedDocblock .= "\n".$annotation;
116-
}
117-
118-
$breaksNbr -= count($annotations);
119-
120-
if ($breaksNbr > 0) {
121-
$compactedDocblock .= str_repeat("\n", $breaksNbr - 1);
122-
$compactedDocblock .= "\n*/";
123-
} else {
124-
// A space is required here to avoid having /***/
125-
$compactedDocblock .= ' */';
126-
}
127-
128-
return $compactedDocblock;
38+
return $this->phpVersionCompactor->compact($contents);
12939
}
13040
}

src/Compactor/Php/Php7.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the box project.
7+
*
8+
* (c) Kevin Herrera <kevin@herrera.io>
9+
* Théo Fidry <theo.fidry@gmail.com>
10+
*
11+
* This source file is subject to the MIT license that is bundled
12+
* with this source code in the file LICENSE.
13+
*/
14+
15+
namespace KevinGH\Box\Compactor\Php;
16+
17+
use function in_array;
18+
use function is_string;
19+
use KevinGH\Box\Annotation\DocblockCompactor;
20+
use function preg_replace;
21+
use RuntimeException;
22+
use function str_repeat;
23+
use function strpos;
24+
use function substr_count;
25+
use const T_COMMENT;
26+
use const T_DOC_COMMENT;
27+
use const T_WHITESPACE;
28+
use function token_get_all;
29+
30+
/**
31+
* A PHP source code compactor copied from Composer.
32+
*
33+
* @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
34+
*
35+
* @author Kevin Herrera <kevin@herrera.io>
36+
* @author Fabien Potencier <fabien@symfony.com>
37+
* @author Jordi Boggiano <j.boggiano@seld.be>
38+
* @author Théo Fidry <theo.fidry@gmail.com>
39+
* @private
40+
*/
41+
final class Php7 implements PhpVersionCompactor
42+
{
43+
private $docblockCompactor;
44+
45+
public function __construct(DocblockCompactor $docblockCompactor)
46+
{
47+
$this->docblockCompactor = $docblockCompactor;
48+
}
49+
50+
public function compact(string $contents): string
51+
{
52+
$output = '';
53+
54+
foreach (token_get_all($contents) as $token) {
55+
if (is_string($token)) {
56+
$output .= $token;
57+
} elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
58+
if (false !== strpos($token[1], '@')) {
59+
try {
60+
$output .= $this->docblockCompactor->compact($token[1]);
61+
} catch (RuntimeException $exception) {
62+
$output .= $token[1];
63+
}
64+
} else {
65+
$output .= str_repeat("\n", substr_count($token[1], "\n"));
66+
}
67+
} elseif (T_WHITESPACE === $token[0]) {
68+
// reduce wide spaces
69+
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
70+
71+
// normalize newlines to \n
72+
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
73+
74+
// trim leading spaces
75+
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
76+
77+
$output .= $whitespace;
78+
} else {
79+
$output .= $token[1];
80+
}
81+
}
82+
83+
return $output;
84+
}
85+
}

src/Compactor/Php/Php8.php

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the box project.
7+
*
8+
* (c) Kevin Herrera <kevin@herrera.io>
9+
* Théo Fidry <theo.fidry@gmail.com>
10+
*
11+
* This source file is subject to the MIT license that is bundled
12+
* with this source code in the file LICENSE.
13+
*/
14+
15+
namespace KevinGH\Box\Compactor\Php;
16+
17+
use KevinGH\Box\Annotation\DocblockCompactor;
18+
use PhpToken;
19+
use function preg_replace;
20+
use RuntimeException;
21+
use function str_repeat;
22+
use function strpos;
23+
use function substr_count;
24+
use const T_COMMENT;
25+
use const T_DOC_COMMENT;
26+
use const T_WHITESPACE;
27+
28+
/**
29+
* A PHP source code compactor copied from Composer.
30+
*
31+
* @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
32+
*
33+
* @author Kevin Herrera <kevin@herrera.io>
34+
* @author Fabien Potencier <fabien@symfony.com>
35+
* @author Jordi Boggiano <j.boggiano@seld.be>
36+
* @author Théo Fidry <theo.fidry@gmail.com>
37+
* @private
38+
*/
39+
final class Php8 implements PhpVersionCompactor
40+
{
41+
private $docblockCompactor;
42+
43+
public function __construct(DocblockCompactor $docblockCompactor)
44+
{
45+
$this->docblockCompactor = $docblockCompactor;
46+
}
47+
48+
public function compact(string $contents): string
49+
{
50+
$output = '';
51+
52+
foreach (PhpToken::tokenize($contents) as $token) {
53+
if ($token->is([T_COMMENT, T_DOC_COMMENT])) {
54+
if (false !== strpos($token->text, '@')) {
55+
try {
56+
$output .= $this->docblockCompactor->compact($token->text);
57+
} catch (RuntimeException $exception) {
58+
$output .= $token[1];
59+
}
60+
} else {
61+
$output .= str_repeat("\n", substr_count($token->text, "\n"));
62+
}
63+
} elseif ($token->is(T_WHITESPACE)) {
64+
// reduce wide spaces
65+
$whitespace = preg_replace('{[ \t]+}', ' ', $token->text);
66+
67+
// normalize newlines to \n
68+
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
69+
70+
// trim leading spaces
71+
$whitespace = preg_replace('{\n +}', "\n", $whitespace);
72+
73+
$output .= $whitespace;
74+
} else {
75+
$output .= $token->text;
76+
}
77+
}
78+
79+
return $output;
80+
}
81+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the box project.
7+
*
8+
* (c) Kevin Herrera <kevin@herrera.io>
9+
* Théo Fidry <theo.fidry@gmail.com>
10+
*
11+
* This source file is subject to the MIT license that is bundled
12+
* with this source code in the file LICENSE.
13+
*/
14+
15+
namespace KevinGH\Box\Compactor\Php;
16+
17+
interface PhpVersionCompactor
18+
{
19+
public function compact(string $contents): string;
20+
}

0 commit comments

Comments
 (0)