Skip to content

Commit

Permalink
Merge pull request #6 from localheinz/feature/package-hash-normalizer
Browse files Browse the repository at this point in the history
Enhancement: Implement PackageHashNormalizer
  • Loading branch information
localheinz authored Jan 13, 2018
2 parents 6f1ca18 + 44bdab4 commit ec0aeb0
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 1 deletion.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ This package makes use of the following normalizers provided by [`localheinz/jso
Additionally, it provides and makes use of the following normalizers:

* [`Localheinz\Composer\Normalize\Normalizer\ConfigHashNormalizer`](#confighashnormalizer)
* [`Localheinz\Composer\Normalize\Normalizer\PackageHashNormalizer`](#packagehashnormalizer)

### `ConfigHashNormalizer`

Expand All @@ -51,6 +52,24 @@ the `ConfigHashNormalizer` will sort the `config` section by key in ascending or

:bulb: Find out more about the `config` section at https://getcomposer.org/doc/06-config.md.

### `PackageHashNormalizer`

If `composer.json` contains any configuration in the

* `conflict`
* `provide`
* `replaces`
* `require`
* `require-dev`
* `suggest`

sections, the `PackageHashNormalizer` will sort the content of these sections.

:bulb: This transfers the behaviour from using the `--sort-packages` or
`sort-packages` configuration flag to other sections. Find out more about
the `--sort-packages` flag and configuration at https://getcomposer.org/doc/06-config.md#sort-packages
and https://getcomposer.org/doc/03-cli.md#require.

## Contributing

Please have a look at [`CONTRIBUTING.md`](.github/CONTRIBUTING.md).
Expand All @@ -62,3 +81,11 @@ Please have a look at [`CODE_OF_CONDUCT.md`](.github/CODE_OF_CONDUCT.md).
## License

This package is licensed using the MIT License.

## Credits

The algorithm for sorting packages in the [`PackageHashNormalizer`](src/Normalizer/PackageHashNormalizer.php) has
been adopted from [`Composer\Json\JsonManipulator::sortPackages()`](https://github.com/composer/composer/blob/1.6.2/src/Composer/Json/JsonManipulator.php#L110-L146)
(originally licensed under MIT by [Nils Adermann](https://github.com/naderman) and [Jordi Boggiano](https://github.com/seldaek)),
which I initially contributed to `composer/composer` with [`composer/composer#3549`](https://github.com/composer/composer/pull/3549)
and [`composer/composer#3872`](https://github.com/composer/composer/pull/3872).
3 changes: 2 additions & 1 deletion src/NormalizePlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public function getCommands(): array
{
return [
new Command\NormalizeCommand(new AutoFormatNormalizer(new ChainNormalizer(
new Normalizer\ConfigHashNormalizer()
new Normalizer\ConfigHashNormalizer(),
new Normalizer\PackageHashNormalizer()
))),
];
}
Expand Down
102 changes: 102 additions & 0 deletions src/Normalizer/PackageHashNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018 Andreas Möller.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://github.com/localheinz/composer-normalize
*/

namespace Localheinz\Composer\Normalize\Normalizer;

use Composer\Repository;
use Localheinz\Json\Normalizer\NormalizerInterface;

final class PackageHashNormalizer implements NormalizerInterface
{
/**
* @var string[]
*/
private static $properties = [
'conflict',
'provide',
'replaces',
'require',
'require-dev',
'suggest',
];

public function normalize(string $json): string
{
$decoded = \json_decode($json);

if (null === $decoded && JSON_ERROR_NONE !== \json_last_error()) {
throw new \InvalidArgumentException(\sprintf(
'"%s" is not valid JSON.',
$json
));
}

$objectProperties = \array_intersect_key(
\get_object_vars($decoded),
\array_flip(self::$properties)
);

if (!\count($objectProperties)) {
return $json;
}

foreach ($objectProperties as $name => $value) {
$decoded->{$name} = $this->sortPackages((array) $decoded->{$name});
}

return \json_encode($decoded);
}

/**
* This code is adopted from composer/composer (originally licensed under MIT by Nils Adermann <naderman@naderman.de>
* and Jordi Boggiano <j.boggiano@seld.be>).
*
* @see https://github.com/composer/composer/blob/1.6.2/src/Composer/Json/JsonManipulator.php#L110-L146
*
* @param string[] $packages
*
* @return string[]
*/
private function sortPackages(array $packages): array
{
$prefix = function ($requirement) {
if (\preg_match(Repository\PlatformRepository::PLATFORM_PACKAGE_REGEX, $requirement)) {
return \preg_replace(
[
'/^php/',
'/^hhvm/',
'/^ext/',
'/^lib/',
'/^\D/',
],
[
'0-$0',
'1-$0',
'2-$0',
'3-$0',
'4-$0',
],
$requirement
);
}

return '5-' . $requirement;
};

\uksort($packages, function ($a, $b) use ($prefix) {
return \strnatcmp($prefix($a), $prefix($b));
});

return $packages;
}
}
99 changes: 99 additions & 0 deletions test/Unit/Normalizer/PackageHashNormalizerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018 Andreas Möller.
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*
* @see https://github.com/localheinz/composer-normalize
*/

namespace Localheinz\Composer\Normalize\Test\Unit\Normalizer;

use Localheinz\Composer\Normalize\Normalizer\PackageHashNormalizer;

final class PackageHashNormalizerTest extends AbstractNormalizerTestCase
{
public function testNormalizeDoesNotModifyOtherProperty()
{
$json = <<<'JSON'
{
"foo": {
"qux": "quux",
"bar": "baz"
}
}
JSON;

$normalizer = new PackageHashNormalizer();

$this->assertSame($json, $normalizer->normalize($json));
}

/**
* @dataProvider providerProperty
*
* @param string $property
*/
public function testNormalizeSortsPackageHashIfPropertyExists(string $property)
{
$json = <<<JSON
{
"${property}": {
"localheinz/test-util": "Provides utilities for tests.",
"hhvm": "Okay",
"lib-baz": "Maybe it helps.",
"localheinz/php-cs-fixer-config": "Provides a configuration factory and multiple rule sets for friendsofphp/php-cs-fixer.",
"ext-foo": "Could be useful",
"php": "Because why not, it's great."
},
"foo": {
"qux": "quux",
"bar": "baz"
}
}
JSON;

$normalized = <<<JSON
{
"${property}": {
"php": "Because why not, it's great.",
"hhvm": "Okay",
"ext-foo": "Could be useful",
"lib-baz": "Maybe it helps.",
"localheinz/php-cs-fixer-config": "Provides a configuration factory and multiple rule sets for friendsofphp/php-cs-fixer.",
"localheinz/test-util": "Provides utilities for tests."
},
"foo": {
"qux": "quux",
"bar": "baz"
}
}
JSON;

$normalizer = new PackageHashNormalizer();

$this->assertSame(\json_encode(\json_decode($normalized)), $normalizer->normalize($json));
}

public function providerProperty(): \Generator
{
$values = [
'conflict',
'provide',
'replaces',
'require',
'require-dev',
'suggest',
];

foreach ($values as $value) {
yield $value => [
$value,
];
}
}
}

0 comments on commit ec0aeb0

Please sign in to comment.