Skip to content

Commit 764eca9

Browse files
Merge pull request #92 from andreaswolf/issue-7
[FEATURE] Add manipulation of composer.json
2 parents 1c3c1dc + 4775887 commit 764eca9

28 files changed

+595
-14
lines changed

.github/workflows/docs.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ jobs:
1313
composer-command:
1414
- name: Generate docs
1515
command: 'docs:generate'
16-
directory: ['typo3-fractor']
16+
directory: ['typo3-fractor', 'fractor-composer-json']
1717

1818
name: ${{ matrix.composer-command.name }}/${{ matrix.directory }}
1919

.github/workflows/lint_test_pull_requests.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
command: test:php
2424
- name: Rector
2525
command: 'rector --dry-run'
26-
directory: [ '', 'extension-installer', 'fractor', 'fractor-xml', 'typo3-fractor', 'fractor-doc-generator', 'fractor-yaml', 'fractor-fluid']
26+
directory: [ '', 'extension-installer', 'fractor', 'fractor-xml', 'typo3-fractor', 'fractor-doc-generator', 'fractor-yaml', 'fractor-fluid', 'fractor-composer-json']
2727
exclude:
2828
- directory: extension-installer
2929
composer-command: {name: 'PHPUnit', command: 'test:php'}

fractor-composer-json/.gitattributes

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
tests export-ignore
2+
.gitattributes export-ignore
3+
.gitignore export-ignore
4+
ecs.php export-ignore
5+
phpstan.neon export-ignore
6+
phpunit.xml export-ignore
7+
README.md export-ignore
8+
rector.php export-ignore

fractor-composer-json/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/vendor/
2+
/composer.lock
3+
.phpunit.cache

fractor-composer-json/composer.json

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"name": "a9f/fractor-composer-json",
3+
"description": "ComposerJson extension for the File Read-Analyse-Change TOol. Allows modifying composer.json files",
4+
"license": "MIT",
5+
"type": "fractor-extension",
6+
"authors": [
7+
{
8+
"name": "Andreas Wolf",
9+
"email": "[email protected]",
10+
"role": "Lead Developer"
11+
}
12+
],
13+
"require": {
14+
"php": "^8.2",
15+
"a9f/fractor": "@dev",
16+
"a9f/fractor-extension-installer": "@dev",
17+
"ergebnis/json-printer": "^3.5",
18+
"eta-orionis/composer-json-manipulator": "^1.0",
19+
"nette/utils": "^4.0",
20+
"webmozart/assert": "^1.11"
21+
},
22+
"require-dev": {
23+
"ergebnis/composer-normalize": "^2.42",
24+
"phpstan/phpstan": "^1.10",
25+
"phpunit/phpunit": "^10.5",
26+
"rector/rector": "^1.0",
27+
"symplify/easy-coding-standard": "^12.1"
28+
},
29+
"repositories": {
30+
"fractor": {
31+
"type": "path",
32+
"url": "../*"
33+
}
34+
},
35+
"autoload": {
36+
"psr-4": {
37+
"a9f\\FractorComposerJson\\": [
38+
"src",
39+
"rules"
40+
]
41+
}
42+
},
43+
"autoload-dev": {
44+
"psr-4": {
45+
"a9f\\FractorComposerJson\\Tests\\": "tests/"
46+
}
47+
},
48+
"config": {
49+
"allow-plugins": {
50+
"a9f/fractor-extension-installer": true,
51+
"ergebnis/composer-normalize": true
52+
},
53+
"sort-packages": true
54+
},
55+
"scripts": {
56+
"analyze:php": "phpstan analyze",
57+
"docs:generate": "fractor-doc-generator generate rules --output-file docs/composer-json-fractor-rules.md",
58+
"rector": "rector",
59+
"style:php:check": "ecs",
60+
"style:php:fix": "ecs --fix",
61+
"test:php": "phpunit"
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use a9f\FractorComposerJson\ComposerJsonFileProcessor;
6+
use a9f\FractorComposerJson\Contract\ComposerJsonFractorRule;
7+
use a9f\FractorComposerJson\Contract\ComposerJsonPrinter;
8+
use a9f\FractorComposerJson\ErgebnisComposerJsonPrinter;
9+
use Ergebnis\Json\Printer\Printer;
10+
use Ergebnis\Json\Printer\PrinterInterface;
11+
use Symfony\Component\DependencyInjection\ContainerBuilder;
12+
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
13+
use function Symfony\Component\DependencyInjection\Loader\Configurator\tagged_iterator;
14+
15+
return static function (ContainerConfigurator $containerConfigurator, ContainerBuilder $containerBuilder): void {
16+
$services = $containerConfigurator->services();
17+
$services->defaults()
18+
->autowire()
19+
->autoconfigure();
20+
21+
$services->load('a9f\\FractorComposerJson\\', __DIR__ . '/../src/');
22+
23+
$services->set(ComposerJsonFileProcessor::class)
24+
->arg('$rules', tagged_iterator('fractor.composer_json_rule'));
25+
26+
$services->set(Printer::class);
27+
$services->alias(ComposerJsonPrinter::class, ErgebnisComposerJsonPrinter::class);
28+
$services->alias(PrinterInterface::class, Printer::class);
29+
$containerBuilder->registerForAutoconfiguration(ComposerJsonFractorRule::class)->addTag(
30+
'fractor.composer_json_rule'
31+
);
32+
};

fractor-composer-json/ecs.php

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return (include __DIR__ . '/../.build/ecs.php')
6+
->withPaths([
7+
__DIR__ . '/config',
8+
__DIR__ . '/src',
9+
__DIR__ . '/tests',
10+
])
11+
;

fractor-composer-json/phpstan.neon

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
parameters:
2+
level: 8
3+
4+
paths:
5+
- src/
6+
- tests/

fractor-composer-json/phpunit.xml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" cacheDirectory=".phpunit.cache">
3+
<testsuites>
4+
<testsuite name="fractor-composer-json">
5+
<directory>tests</directory>
6+
</testsuite>
7+
</testsuites>
8+
<source>
9+
<include>
10+
<directory>./src</directory>
11+
</include>
12+
</source>
13+
</phpunit>

fractor-composer-json/rector.php

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
return (include __DIR__ . '/../.build/rector.php')
6+
->withPaths([
7+
__DIR__ . '/config',
8+
__DIR__ . '/src',
9+
__DIR__ . '/tests',
10+
]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
namespace a9f\FractorComposerJson;
5+
6+
use a9f\FractorComposerJson\Contract\ComposerJson;
7+
use a9f\FractorComposerJson\Contract\ComposerJsonFractorRule;
8+
use a9f\FractorComposerJson\ValueObject\PackageAndVersion;
9+
use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample;
10+
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
11+
use Webmozart\Assert\Assert;
12+
13+
final class AddPackageToRequireComposerJsonFractorRule implements ComposerJsonFractorRule
14+
{
15+
/**
16+
* @var PackageAndVersion[]
17+
*/
18+
private array $packagesAndVersions = [];
19+
20+
public function getRuleDefinition(): RuleDefinition
21+
{
22+
return new RuleDefinition('Add package to "require" in `composer.json`', [new ConfiguredCodeSample(
23+
<<<'CODE_SAMPLE'
24+
{
25+
}
26+
CODE_SAMPLE
27+
,
28+
<<<'CODE_SAMPLE'
29+
{
30+
"require": {
31+
"symfony/console": "^3.4"
32+
}
33+
}
34+
CODE_SAMPLE
35+
,
36+
[new PackageAndVersion('symfony/console', '^3.4')]
37+
),
38+
]);
39+
}
40+
41+
public function refactor(ComposerJson $composerJson): void
42+
{
43+
foreach ($this->packagesAndVersions as $packageAndVersion) {
44+
$composerJson->addRequiredPackage($packageAndVersion);
45+
}
46+
}
47+
48+
public function configure(array $configuration): void
49+
{
50+
Assert::allIsAOf($configuration, PackageAndVersion::class);
51+
52+
$this->packagesAndVersions = $configuration;
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorComposerJson;
6+
7+
use a9f\Fractor\Application\ValueObject\File;
8+
use a9f\FractorComposerJson\Contract\ComposerJson;
9+
use a9f\FractorComposerJson\ValueObject\EtaOrionisComposerJson;
10+
11+
final class ComposerJsonFactory
12+
{
13+
public function createFromFile(File $file): ComposerJson
14+
{
15+
return EtaOrionisComposerJson::fromFile($file);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorComposerJson;
6+
7+
use a9f\Fractor\Application\Contract\FileProcessor;
8+
use a9f\Fractor\Application\ValueObject\AppliedRule;
9+
use a9f\Fractor\Application\ValueObject\File;
10+
use a9f\Fractor\ValueObject\Indent;
11+
use a9f\FractorComposerJson\Contract\ComposerJsonFractorRule;
12+
use a9f\FractorComposerJson\Contract\ComposerJsonPrinter;
13+
14+
final readonly class ComposerJsonFileProcessor implements FileProcessor
15+
{
16+
/**
17+
* @param iterable<ComposerJsonFractorRule> $rules
18+
*/
19+
public function __construct(
20+
private iterable $rules,
21+
private ComposerJsonPrinter $composerJsonPrinter,
22+
private ComposerJsonFactory $composerJsonFactory
23+
) {
24+
}
25+
26+
public function handle(File $file): void
27+
{
28+
$composerJson = $this->composerJsonFactory->createFromFile($file);
29+
$oldComposerJson = $this->composerJsonFactory->createFromFile($file);
30+
$ident = Indent::fromFile($file);
31+
32+
foreach ($this->rules as $rule) {
33+
$rule->refactor($composerJson);
34+
35+
if ($oldComposerJson->getJsonArray() !== $composerJson->getJsonArray()) {
36+
$file->changeFileContent($this->composerJsonPrinter->printToString($ident, $composerJson));
37+
$file->addAppliedRule(AppliedRule::fromRule($rule));
38+
}
39+
}
40+
}
41+
42+
public function canHandle(File $file): bool
43+
{
44+
return $file->getFileName() === 'composer.json';
45+
}
46+
47+
public function allowedFileExtensions(): array
48+
{
49+
return ['json'];
50+
}
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorComposerJson\Contract;
6+
7+
use a9f\FractorComposerJson\ValueObject\PackageAndVersion;
8+
9+
interface ComposerJson
10+
{
11+
/**
12+
* @return mixed[]
13+
*/
14+
public function getJsonArray(): array;
15+
16+
public function addRequiredPackage(PackageAndVersion $packageAndVersion): void;
17+
18+
public function toJsonString(): string;
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorComposerJson\Contract;
6+
7+
use a9f\Fractor\Application\Contract\ConfigurableFractorRule;
8+
use a9f\Fractor\Application\Contract\FractorRule;
9+
10+
interface ComposerJsonFractorRule extends FractorRule, ConfigurableFractorRule
11+
{
12+
public function refactor(ComposerJson $composerJson): void;
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorComposerJson\Contract;
6+
7+
use a9f\Fractor\ValueObject\Indent;
8+
9+
interface ComposerJsonPrinter
10+
{
11+
public function printToString(Indent $indent, ComposerJson $composerJson): string;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace a9f\FractorComposerJson;
6+
7+
use a9f\Fractor\ValueObject\Indent;
8+
use a9f\FractorComposerJson\Contract\ComposerJson;
9+
use a9f\FractorComposerJson\Contract\ComposerJsonPrinter;
10+
use Ergebnis\Json\Printer\PrinterInterface;
11+
12+
final readonly class ErgebnisComposerJsonPrinter implements ComposerJsonPrinter
13+
{
14+
public function __construct(
15+
private PrinterInterface $printer
16+
) {
17+
}
18+
19+
public function printToString(Indent $indent, ComposerJson $composerJson): string
20+
{
21+
return $this->printer->print($composerJson->toJsonString(), $indent->toString());
22+
}
23+
}

0 commit comments

Comments
 (0)