Passed
Pull Request — master (#315)
by Théo
06:13 queued 01:44
created

Php   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 12
eloc 37
dl 0
loc 87
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B compactContent() 0 43 7
A compactAnnotations() 0 25 4
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the box project.
7
 *
8
 * (c) Kevin Herrera <[email protected]>
9
 *     Théo Fidry <[email protected]>
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;
16
17
use KevinGH\Box\Annotation\DocblockAnnotationParser;
18
use RuntimeException;
19
use const T_COMMENT;
20
use const T_DOC_COMMENT;
21
use const T_WHITESPACE;
22
use function count;
23
use function in_array;
24
use function is_string;
25
use function preg_replace;
26
use function str_repeat;
27
use function strpos;
28
use function substr_count;
29
use function token_get_all;
30
31
/**
32
 * A PHP source code compactor copied from Composer.
33
 *
34
 * @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
35
 *
36
 * @author Kevin Herrera <[email protected]>
37
 * @author Fabien Potencier <[email protected]>
38
 * @author Jordi Boggiano <[email protected]>
39
 * @author Théo Fidry <[email protected]>
40
 * @private
41
 */
42
final class Php extends FileExtensionCompactor
43
{
44
    private $annotationParser;
45
46
    /**
47
     * {@inheritdoc}
48
     */
49
    public function __construct(DocblockAnnotationParser $annotationParser, array $extensions = ['php'])
50
    {
51
        parent::__construct($extensions);
52
53
        $this->annotationParser = $annotationParser;
54
    }
55
56
    /**
57
     * {@inheritdoc}
58
     */
59
    protected function compactContent(string $contents): string
60
    {
61
        // TODO: refactor this piece of code
62
        // - strip down blank spaces
63
        // - remove useless spaces
64
        // - strip down comments except Doctrine style annotations unless whitelisted -> BC break to document;
65
        //   Alternatively provide an easy way to strip down all "regular" annotations such as @package, @param
66
        //   & co.
67
        // - completely remove comments & docblocks if empty
68
        // TODO regarding the doc: it current has its own `annotations` entry. Maybe it would be best to
69
        // include it as a sub element of `compactors`
70
        $output = '';
71
72
        foreach (token_get_all($contents) as $token) {
73
            if (is_string($token)) {
74
                $output .= $token;
75
            } elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
76
                if (false !== strpos($token[1], '@')) {
77
                    try {
78
                        $output .= $this->compactAnnotations($token[1]);
79
                    } catch (RuntimeException $exception) {
80
                        $output .= $token[1];
81
                    }
82
                } else {
83
                    $output .= str_repeat("\n", substr_count($token[1], "\n"));
84
                }
85
            } elseif (T_WHITESPACE === $token[0]) {
86
                // reduce wide spaces
87
                $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
88
89
                // normalize newlines to \n
90
                $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
91
92
                // trim leading spaces
93
                $whitespace = preg_replace('{\n +}', "\n", $whitespace);
94
95
                $output .= $whitespace;
96
            } else {
97
                $output .= $token[1];
98
            }
99
        }
100
101
        return $output;
102
    }
103
104
    private function compactAnnotations(string $docblock): string
105
    {
106
        $breaks = substr_count($docblock, "\n");
107
        $compactedDocblock = '/**';
108
109
        $annotations = $this->annotationParser->parse($docblock);
110
111
        if ([] === $annotations) {
112
            return str_repeat("\n", $breaks);
113
        }
114
115
        foreach ($annotations as $annotation) {
116
            $compactedDocblock .= "\n".$annotation;
117
        }
118
119
        $breaks -= count($annotations);
120
121
        if ($breaks > 0) {
122
            $compactedDocblock .= str_repeat("\n", $breaks - 1);
123
            $compactedDocblock .= "\n*/";
124
        } else {
125
            $compactedDocblock .= ' */';
126
        }
127
128
        return $compactedDocblock;
129
    }
130
}
131