Passed
Pull Request — master (#315)
by Théo
02:54
created

Php::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
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 Exception;
18
use KevinGH\Box\Annotation\AnnotationDumper;
19
use KevinGH\Box\Annotation\Convert\ToString;
0 ignored issues
show
Bug introduced by
The type KevinGH\Box\Annotation\Convert\ToString was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use KevinGH\Box\Annotation\DocblockParser;
21
use const T_COMMENT;
22
use const T_DOC_COMMENT;
23
use const T_WHITESPACE;
24
use function count;
25
use function in_array;
26
use function is_string;
27
use function preg_replace;
28
use function str_repeat;
29
use function strpos;
30
use function substr_count;
31
use function token_get_all;
32
33
/**
34
 * A PHP source code compactor copied from Composer.
35
 *
36
 * @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
37
 *
38
 * @author Kevin Herrera <[email protected]>
39
 * @author Fabien Potencier <[email protected]>
40
 * @author Jordi Boggiano <[email protected]>
41
 * @author Théo Fidry <[email protected]>
42
 * @private
43
 */
44
final class Php extends FileExtensionCompactor
45
{
46
    private $converter;
47
    private $tokenizer;
48
49
    /**
50
     * {@inheritdoc}
51
     */
52
    public function __construct(DocblockParser $tokenizer, array $extensions = ['php'])
53
    {
54
        parent::__construct($extensions);
55
56
        $this->converter = new ToString();
57
        $this->tokenizer = $tokenizer;
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    protected function compactContent(string $contents): string
64
    {
65
        // TODO: refactor this piece of code
66
        // - strip down blank spaces
67
        // - remove useless spaces
68
        // - strip down comments except Doctrine style annotations unless whitelisted -> BC break to document;
69
        //   Alternatively provide an easy way to strip down all "regular" annotations such as @package, @param
70
        //   & co.
71
        // - completely remove comments & docblocks if empty
72
        // TODO regarding the doc: it current has its own `annotations` entry. Maybe it would be best to
73
        // include it as a sub element of `compactors`
74
        $output = '';
75
76
        foreach (token_get_all($contents) as $token) {
77
            if (is_string($token)) {
78
                $output .= $token;
79
            } elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
80
                if ($this->tokenizer && false !== strpos($token[1], '@')) {
81
                    try {
82
                        $output .= $this->compactAnnotations($token[1]);
83
                    } catch (Exception $exception) {
84
                        $output .= $token[1];
85
                    }
86
                } else {
87
                    $output .= str_repeat("\n", substr_count($token[1], "\n"));
88
                }
89
            } elseif (T_WHITESPACE === $token[0]) {
90
                // reduce wide spaces
91
                $whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);
92
93
                // normalize newlines to \n
94
                $whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);
95
96
                // trim leading spaces
97
                $whitespace = preg_replace('{\n +}', "\n", $whitespace);
98
99
                $output .= $whitespace;
100
            } else {
101
                $output .= $token[1];
102
            }
103
        }
104
105
        return $output;
106
    }
107
108
    private function compactAnnotations(string $docblock): string
109
    {
110
        $annotations = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $annotations is dead and can be removed.
Loading history...
111
        $index = -1;
0 ignored issues
show
Unused Code introduced by
The assignment to $index is dead and can be removed.
Loading history...
112
        $inside = 0;
0 ignored issues
show
Unused Code introduced by
The assignment to $inside is dead and can be removed.
Loading history...
113
        $nodes = $this->tokenizer->parse($docblock);
114
115
        if (0 === $nodes->getChildrenNumber()) {
116
            return str_repeat("\n", substr_count($docblock, "\n"));
117
        }
118
119
//        foreach ($nodes->getChildren() as $child) {
120
//            if ((0 === $inside) && (DocLexer::T_AT === $child[0])) {
121
//                ++$index;
122
//            } elseif (DocLexer::T_OPEN_PARENTHESIS === $child[0]) {
123
//                ++$inside;
124
//            } elseif (DocLexer::T_CLOSE_PARENTHESIS === $child[0]) {
125
//                --$inside;
126
//            }
127
//
128
//            if (!isset($annotations[$index])) {
129
//                $annotations[$index] = [];
130
//            }
131
//
132
//            $annotations[$index][] = $child;
133
//        }
134
135
        $breaks = substr_count($docblock, "\n");
136
        $docblock = '/**';
137
138
        $compacted = (new AnnotationDumper())->dump($nodes);
139
        foreach ($compacted as $annotation) {
140
            $docblock .= "\n".$annotation;
141
        }
142
143
        $breaks -= count($compacted);
144
145
        if ($breaks > 0) {
146
            $docblock .= str_repeat("\n", $breaks - 1);
147
            $docblock .= "\n*/";
148
        } else {
149
            $docblock .= ' */';
150
        }
151
152
        return $docblock;
153
    }
154
}
155