Completed
Push — master ( 550011...0647fd )
by Théo
16:20 queued 07:57
created

NodeTraverser::wrapInNamespace()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 7.0099

Importance

Changes 0
Metric Value
cc 7
nc 7
nop 1
dl 0
loc 32
ccs 16
cts 17
cp 0.9412
crap 7.0099
rs 8.4746
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the humbug/php-scoper package.
7
 *
8
 * Copyright (c) 2017 Théo FIDRY <[email protected]>,
9
 *                    Pádraic Brady <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Humbug\PhpScoper\PhpParser;
16
17
use PhpParser\Node;
18
use PhpParser\Node\Name;
19
use PhpParser\Node\Stmt\Declare_;
20
use PhpParser\Node\Stmt\GroupUse;
21
use PhpParser\Node\Stmt\InlineHTML;
22
use PhpParser\Node\Stmt\Namespace_;
23
use PhpParser\Node\Stmt\Use_;
24
use PhpParser\Node\Stmt\UseUse;
25
use PhpParser\NodeTraverser as PhpParserNodeTraverser;
26
use function array_slice;
27
use function array_values;
28
use function count;
29
30
/**
31
 * @private
32
 */
33
final class NodeTraverser extends PhpParserNodeTraverser
34
{
35
    private $prefix;
36
37 10
    public function __construct(string $prefix)
38
    {
39 10
        parent::__construct();
40
41 10
        $this->prefix = $prefix;
42
    }
43
44
    /**
45
     * @inheritdoc
46
     */
47 10
    public function traverse(array $nodes): array
48
    {
49 10
        $nodes = $this->wrapInNamespace($nodes);
50 10
        $nodes = $this->replaceGroupUseStatements($nodes);
51
52 10
        return parent::traverse($nodes);
53
    }
54
55
    /**
56
     * Wrap the statements in a namespace when necessary:.
57
     *
58
     * ```php
59
     * #!/usr/bin/env php
60
     * <?php declare(strict_types=1);
61
     *
62
     * // A small comment
63
     *
64
     * if (\true) {
65
     *  echo "yo";
66
     * }
67
     * ```
68
     *
69
     * Will result in:
70
     *
71
     * ```php
72
     * #!/usr/bin/env php
73
     * <?php declare(strict_types=1);
74
     *
75
     * // A small comment
76
     *
77
     * namespace {
78
     *     if (\true) {
79
     *      echo "yo";
80
     *     }
81
     * }
82
     * ```
83
     *
84
     * @param Node[] $nodes
85
     *
86
     * @return Node[]
87
     */
88 10
    private function wrapInNamespace(array $nodes): array
89
    {
90 10
        if ([] === $nodes) {
91
            return $nodes;
92
        }
93
94 10
        $nodes = array_values($nodes);
95
96 10
        $firstRealStatementIndex = 0;
97 10
        $realStatements = [];
98
99 10
        foreach ($nodes as $i => $node) {
100 10
            if ($node instanceof Declare_ || $node instanceof InlineHTML) {
101 1
                continue;
102
            }
103
104 10
            $firstRealStatementIndex = $i;
105 10
            $realStatements = array_slice($nodes, $i);
106
107 10
            break;
108
        }
109
110 10
        $firstRealStatement = current($realStatements);
111
112 10
        if (false !== $firstRealStatement && false === ($firstRealStatement instanceof Namespace_)) {
113 7
            $wrappedStatements = new Namespace_(null, $realStatements);
114
115 7
            array_splice($nodes, $firstRealStatementIndex, count($realStatements), [$wrappedStatements]);
116
        }
117
118 10
        return $nodes;
119
    }
120
121
    /**
122
     * @param Node[] $nodes
123
     *
124
     * @return Node[]
125
     */
126 10
    private function replaceGroupUseStatements(array $nodes): array
127
    {
128 10
        foreach ($nodes as $node) {
129 10
            if (false === ($node instanceof Namespace_)) {
130 1
                continue;
131
            }
132
133
            /** @var Namespace_ $node */
134 10
            $statements = $node->stmts;
135
136 10
            $newStatements = [];
137
138 10
            foreach ($statements as $statement) {
139 10
                if ($statement instanceof GroupUse) {
140
                    $uses_ = $this->createUses_($statement);
141
142
                    array_splice($newStatements, count($newStatements), 0, $uses_);
143
                } else {
144 10
                    $newStatements[] = $statement;
145
                }
146
            }
147
148 10
            $node->stmts = $newStatements;
149
        }
150
151 10
        return $nodes;
152
    }
153
154
    /**
155
     * @param GroupUse $node
156
     *
157
     * @return Use_[]
158
     */
159
    private function createUses_(GroupUse $node): array
160
    {
161
        return array_map(
162
            static function (UseUse $use) use ($node): Use_ {
163
                $newUse = new UseUse(
164
                    Name::concat($node->prefix, $use->name, $use->name->getAttributes()),
165
                    $use->alias,
166
                    $use->type,
167
                    $use->getAttributes()
168
                );
169
170
                return new Use_(
171
                    [$newUse],
172
                    $node->type,
173
                    $node->getAttributes()
174
                );
175
            },
176
            $node->uses
177
        );
178
    }
179
}
180