Skip to content

Commit b6e499c

Browse files
authored
Scope Composer autoloader (#52)
Scope composer autoloader by altering the `composer.json` files directly which requires a `composer dump-autoload` to generate the correct autoloaders.
1 parent f56a642 commit b6e499c

File tree

14 files changed

+657
-131
lines changed

14 files changed

+657
-131
lines changed

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ build: bin/php-scoper
1919
rm composer.lock
2020
composer install --no-dev --prefer-dist --classmap-authoritative
2121
php -d zend.enable_gc=0 bin/php-scoper add-prefix --force
22+
cd build && composer dump-autoload --classmap-authoritative
2223
php -d zend.enable_gc=0 $(BOX) build
2324
mv build/bin/php-scoper.phar bin/
2425
composer install

src/Handler/HandleAddPrefix.php

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
use Humbug\PhpScoper\Scoper;
1919
use Humbug\PhpScoper\Throwable\Exception\ParsingException;
2020
use Humbug\PhpScoper\Throwable\Exception\RuntimeException;
21-
use PhpParser\Error;
21+
use PhpParser\Error as PhpParserError;
2222
use SplFileInfo;
2323
use Symfony\Component\Filesystem\Filesystem;
2424
use Symfony\Component\Finder\Finder;
@@ -155,14 +155,9 @@ private function scopeFiles(array $files, string $prefix, ConsoleLogger $logger)
155155

156156
private function scopeFile(string $inputFilePath, string $outputFilePath, string $prefix, ConsoleLogger $logger)
157157
{
158-
$fileContent = file_get_contents($inputFilePath);
159-
160158
try {
161-
$scoppedContent = (1 === preg_match('/.*\.php$/', $inputFilePath))
162-
? $this->scoper->scope($fileContent, $prefix)
163-
: $fileContent
164-
;
165-
} catch (Error $error) {
159+
$scoppedContent = $this->scoper->scope($inputFilePath, $prefix);
160+
} catch (PhpParserError $error) {
166161
throw new ParsingException(
167162
sprintf(
168163
'Could not parse the file "%s".',

src/Scoper.php

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,58 +14,19 @@
1414

1515
namespace Humbug\PhpScoper;
1616

17-
use Humbug\PhpScoper\NodeVisitor\FullyQualifiedNamespaceUseScoperNodeVisitor;
18-
use Humbug\PhpScoper\NodeVisitor\GroupUseNamespaceScoperNodeVisitor;
19-
use Humbug\PhpScoper\NodeVisitor\IgnoreNamespaceScoperNodeVisitor;
20-
use Humbug\PhpScoper\NodeVisitor\NamespaceScoperNodeVisitor;
21-
use Humbug\PhpScoper\NodeVisitor\ParentNodeVisitor;
22-
use Humbug\PhpScoper\NodeVisitor\UseNamespaceScoperNodeVisitor;
2317
use Humbug\PhpScoper\Throwable\Exception\ParsingException;
24-
use PhpParser\Error;
25-
use PhpParser\NodeTraverser;
26-
use PhpParser\Parser;
27-
use PhpParser\PrettyPrinter\Standard;
2818

29-
/**
30-
* @final
31-
*/
32-
class Scoper
19+
interface Scoper
3320
{
34-
private $parser;
35-
36-
public function __construct(Parser $parser)
37-
{
38-
$this->parser = $parser;
39-
}
40-
4121
/**
42-
* @param string $content Content of the file to scope
43-
* @param string $prefix Prefix to apply to the file
22+
* Scope AKA. apply the given prefix to the file in the appropriate way.
23+
*
24+
* @param string $filePath File to scope
25+
* @param string $prefix Prefix to apply to the file
4426
*
4527
* @throws ParsingException
4628
*
4729
* @return string Content of the file with the prefix applied
4830
*/
49-
public function scope(string $content, string $prefix): string
50-
{
51-
$traverser = new NodeTraverser();
52-
$traverser->addVisitor(new ParentNodeVisitor());
53-
$traverser->addVisitor(new IgnoreNamespaceScoperNodeVisitor());
54-
$traverser->addVisitor(new GroupUseNamespaceScoperNodeVisitor($prefix));
55-
$traverser->addVisitor(new NamespaceScoperNodeVisitor($prefix));
56-
$traverser->addVisitor(new UseNamespaceScoperNodeVisitor($prefix));
57-
$traverser->addVisitor(new FullyQualifiedNamespaceUseScoperNodeVisitor($prefix));
58-
59-
try {
60-
$statements = $this->parser->parse($content);
61-
} catch (Error $error) {
62-
throw new ParsingException($error->getMessage(), 0, $error);
63-
}
64-
65-
$statements = $traverser->traverse($statements);
66-
67-
$prettyPrinter = new Standard();
68-
69-
return $prettyPrinter->prettyPrintFile($statements)."\n";
70-
}
31+
public function scope(string $filePath, string $prefix): string;
7132
}

src/Scoper/ComposerScoper.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 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\Scoper;
16+
17+
use Humbug\PhpScoper\Scoper;
18+
19+
final class ComposerScoper implements Scoper
20+
{
21+
private $decoratedScoper;
22+
23+
public function __construct(Scoper $decoratedScoper)
24+
{
25+
$this->decoratedScoper = $decoratedScoper;
26+
}
27+
28+
/**
29+
* Scopes PHP and JSON files related to Composer.
30+
*
31+
* {@inheritdoc}
32+
*/
33+
public function scope(string $filePath, string $prefix): string
34+
{
35+
if (preg_match('/composer\.lock$/', $filePath)) {
36+
return file_get_contents($filePath);
37+
}
38+
39+
if (1 !== preg_match('/composer\.json$/', $filePath)) {
40+
return $this->decoratedScoper->scope($filePath, $prefix);
41+
}
42+
43+
$decodedJson = json_decode(
44+
file_get_contents($filePath),
45+
true
46+
);
47+
48+
if (isset($decodedJson['autoload'])) {
49+
$decodedJson['autoload'] = $this->prefixAutoloaders($decodedJson['autoload'], $prefix);
50+
}
51+
52+
if (isset($decodedJson['autoload-dev'])) {
53+
$decodedJson['autoload-dev'] = $this->prefixAutoloaders($decodedJson['autoload-dev'], $prefix);
54+
}
55+
56+
return json_encode(
57+
$decodedJson,
58+
JSON_PRETTY_PRINT
59+
);
60+
}
61+
62+
private function prefixAutoloaders(array $autoloader, string $prefix): array
63+
{
64+
if (isset($autoloader['psr-4'])) {
65+
$autoloader['psr-4'] = $this->prefixAutoloader($autoloader['psr-4'], $prefix);
66+
}
67+
68+
return $autoloader;
69+
}
70+
71+
private function prefixAutoloader(array $autoloader, string $prefix): array
72+
{
73+
$loader = [];
74+
75+
foreach ($autoloader as $namespace => $paths) {
76+
$loader[sprintf('%s\\%s', $prefix, $namespace)] = $paths;
77+
}
78+
79+
return $loader;
80+
}
81+
}

src/Scoper/NullScoper.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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\Scoper;
16+
17+
use Humbug\PhpScoper\Scoper;
18+
19+
final class NullScoper implements Scoper
20+
{
21+
/**
22+
* @inheritdoc
23+
*/
24+
public function scope(string $filePath, string $prefix): string
25+
{
26+
return file_get_contents($filePath);
27+
}
28+
}

src/Scoper/PhpScoper.php

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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\Scoper;
16+
17+
use Humbug\PhpScoper\NodeVisitor\FullyQualifiedNamespaceUseScoperNodeVisitor;
18+
use Humbug\PhpScoper\NodeVisitor\GroupUseNamespaceScoperNodeVisitor;
19+
use Humbug\PhpScoper\NodeVisitor\IgnoreNamespaceScoperNodeVisitor;
20+
use Humbug\PhpScoper\NodeVisitor\NamespaceScoperNodeVisitor;
21+
use Humbug\PhpScoper\NodeVisitor\ParentNodeVisitor;
22+
use Humbug\PhpScoper\NodeVisitor\UseNamespaceScoperNodeVisitor;
23+
use Humbug\PhpScoper\Scoper;
24+
use PhpParser\Error as PhpParserError;
25+
use PhpParser\NodeTraverser;
26+
use PhpParser\NodeTraverserInterface;
27+
use PhpParser\Parser;
28+
use PhpParser\PrettyPrinter\Standard;
29+
30+
final class PhpScoper implements Scoper
31+
{
32+
/** @internal */
33+
const FILE_PATTERN = '/.*\.php$/';
34+
35+
private $parser;
36+
private $decoratedScoper;
37+
38+
public function __construct(Parser $parser, Scoper $decoratedScoper)
39+
{
40+
$this->parser = $parser;
41+
$this->decoratedScoper = $decoratedScoper;
42+
}
43+
44+
/**
45+
* Scopes PHP files.
46+
*
47+
* {@inheritdoc}
48+
*
49+
* @throws PhpParserError
50+
*/
51+
public function scope(string $filePath, string $prefix): string
52+
{
53+
if (1 !== preg_match(self::FILE_PATTERN, $filePath)) {
54+
return $this->decoratedScoper->scope($filePath, $prefix);
55+
}
56+
57+
$content = file_get_contents($filePath);
58+
59+
$traverser = $this->createTraverser($prefix);
60+
61+
$statements = $this->parser->parse($content);
62+
$statements = $traverser->traverse($statements);
63+
64+
$prettyPrinter = new Standard();
65+
66+
return $prettyPrinter->prettyPrintFile($statements)."\n";
67+
}
68+
69+
private function createTraverser(string $prefix): NodeTraverserInterface
70+
{
71+
$traverser = new NodeTraverser();
72+
73+
$traverser->addVisitor(new ParentNodeVisitor());
74+
$traverser->addVisitor(new IgnoreNamespaceScoperNodeVisitor());
75+
$traverser->addVisitor(new GroupUseNamespaceScoperNodeVisitor($prefix));
76+
$traverser->addVisitor(new NamespaceScoperNodeVisitor($prefix));
77+
$traverser->addVisitor(new UseNamespaceScoperNodeVisitor($prefix));
78+
$traverser->addVisitor(new FullyQualifiedNamespaceUseScoperNodeVisitor($prefix));
79+
80+
return $traverser;
81+
}
82+
}

src/functions.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
use Humbug\PhpScoper\Console\Application;
1818
use Humbug\PhpScoper\Console\Command\AddPrefixCommand;
1919
use Humbug\PhpScoper\Handler\HandleAddPrefix;
20+
use Humbug\PhpScoper\Scoper\ComposerScoper;
21+
use Humbug\PhpScoper\Scoper\NullScoper;
22+
use Humbug\PhpScoper\Scoper\PhpScoper;
2023
use PackageVersions\Versions;
2124
use PhpParser\Parser;
2225
use PhpParser\ParserFactory;
@@ -34,9 +37,7 @@ function create_application(): SymfonyApplication
3437
new AddPrefixCommand(
3538
new Filesystem(),
3639
new HandleAddPrefix(
37-
new Scoper(
38-
create_parser()
39-
)
40+
create_scoper()
4041
)
4142
),
4243
]);
@@ -56,6 +57,19 @@ function get_version(): string
5657
return (1 === preg_match('/9{7}/', $prettyVersion)) ? $commitHash : $prettyVersion;
5758
}
5859

60+
/**
61+
* @private
62+
*/
63+
function create_scoper(): Scoper
64+
{
65+
return new ComposerScoper(
66+
new PhpScoper(
67+
create_parser(),
68+
new NullScoper()
69+
)
70+
);
71+
}
72+
5973
/**
6074
* @private
6175
*/

0 commit comments

Comments
 (0)