Skip to content

Commit bc274fe

Browse files
committed
Enhancement: Let ConfigHashNormalizer recursively sort hashes by key
1 parent 55e2515 commit bc274fe

5 files changed

Lines changed: 99 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## Unreleased
88

9-
For a full diff see [`0.14.1...main`][0.14.1...main].
9+
For a full diff see [`1.0.0...main`][1.0.0...main].
10+
11+
## [`1.0.0`][1.0.0]
12+
13+
For a full diff see [`0.14.1...1.0.0`][0.14.1...1.0.0].
14+
15+
### Changed
16+
17+
* Adjusted `Vendor\Composer\ConfigHashNormalizer` to recursively sort hashes by key ([#424]), by [@localheinz]
1018

1119
## [`0.14.1`][0.14.1]
1220

@@ -284,6 +292,7 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0].
284292
[0.13.1]: https://github.com/ergebnis/json-normalizer/releases/tag/0.13.1
285293
[0.14.0]: https://github.com/ergebnis/json-normalizer/releases/tag/0.14.0
286294
[0.14.1]: https://github.com/ergebnis/json-normalizer/releases/tag/0.14.1
295+
[1.0.0]: https://github.com/ergebnis/json-normalizer/releases/tag/1.0.0
287296

288297
[5d8b3e2...0.1.0]: https://github.com/ergebnis/json-normalizer/compare/5d8b3e2...0.1.0
289298
[0.1.0...0.2.0]: https://github.com/ergebnis/json-normalizer/compare/0.1.0...0.2.0
@@ -304,7 +313,8 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0].
304313
[0.13.0...0.13.1]: https://github.com/ergebnis/json-normalizer/compare/0.13.0...0.13.1
305314
[0.13.1...0.14.0]: https://github.com/ergebnis/json-normalizer/compare/0.13.1...0.14.0
306315
[0.14.0...0.14.1]: https://github.com/ergebnis/json-normalizer/compare/0.14.0...0.14.1
307-
[0.14.1...main]: https://github.com/ergebnis/json-normalizer/compare/0.14.1...main
316+
[0.14.1...1.0.0]: https://github.com/ergebnis/json-normalizer/compare/0.14.1...1.0.0
317+
[1.0.0...main]: https://github.com/ergebnis/json-normalizer/compare/1.0.0...main
308318

309319
[#1]: https://github.com/ergebnis/json-normalizer/pull/1
310320
[#2]: https://github.com/ergebnis/json-normalizer/pull/2
@@ -367,6 +377,7 @@ For a full diff see [`5d8b3e2...0.1.0`][5d8b3e2...0.1.0].
367377
[#335]: https://github.com/ergebnis/json-normalizer/pull/335
368378
[#384]: https://github.com/ergebnis/json-normalizer/pull/384
369379
[#423]: https://github.com/ergebnis/json-normalizer/pull/423
380+
[#424]: https://github.com/ergebnis/json-normalizer/pull/424
370381

371382
[@BackEndTea]: https://github.com/BackEndTea
372383
[@ergebnis]: https://github.com/ergebnis

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ When `composer.json` contains any configuration in the
389389
* `extra`
390390
* `scripts-descriptions`
391391

392-
sections, the `Vendor\Composer\ConfigHashNormalizer` will sort the content of these sections by key in ascending order.
392+
sections, the `Vendor\Composer\ConfigHashNormalizer` will sort the content of these sections by key in ascending order. If a value is an object, it will continue to sort its properties by name.
393393

394394
:bulb: Find out more about the `config` section at [Composer: The composer.json schema](https://getcomposer.org/doc/06-config.md).
395395

psalm-baseline.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@
6060
</MixedReturnStatement>
6161
</file>
6262
<file src="src/Vendor/Composer/ConfigHashNormalizer.php">
63+
<MixedArgument occurrences="2">
64+
<code>$value</code>
65+
<code>$value</code>
66+
</MixedArgument>
6367
<MixedAssignment occurrences="1">
6468
<code>$value</code>
6569
</MixedAssignment>
66-
<UnusedVariable occurrences="1">
67-
<code>$value</code>
68-
</UnusedVariable>
6970
</file>
7071
<file src="src/Vendor/Composer/PackageHashNormalizer.php">
7172
<MixedAssignment occurrences="1">

src/Vendor/Composer/ConfigHashNormalizer.php

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,36 @@ public function normalize(Json $json): Json
4848
}
4949

5050
foreach ($objectProperties as $name => $value) {
51-
$config = (array) $decoded->{$name};
52-
53-
if (0 === \count($config)) {
54-
continue;
55-
}
56-
57-
\ksort($config);
58-
59-
$decoded->{$name} = $config;
51+
$decoded->{$name} = self::sortByKey($value);
6052
}
6153

6254
/** @var string $encoded */
6355
$encoded = \json_encode($decoded);
6456

6557
return Json::fromEncoded($encoded);
6658
}
59+
60+
/**
61+
* @param null|array|bool|false|\stdClass|string $value
62+
*
63+
* @return null|array|bool|false|\stdClass|string
64+
*/
65+
private static function sortByKey($value)
66+
{
67+
if (!\is_object($value)) {
68+
return $value;
69+
}
70+
71+
$sorted = (array) $value;
72+
73+
if ([] === $sorted) {
74+
return $value;
75+
}
76+
77+
\ksort($sorted);
78+
79+
return \array_map(static function ($value) {
80+
return self::sortByKey($value);
81+
}, $sorted);
82+
}
6783
}

test/Unit/Vendor/Composer/ConfigHashNormalizerTest.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,62 @@ public function testNormalizeSortsConfigHashIfPropertyExists(string $property):
140140
self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded());
141141
}
142142

143+
/**
144+
* @dataProvider provideProperty
145+
*/
146+
public function testNormalizeSortsConfigHashRecursivelyIfPropertyExists(string $property): void
147+
{
148+
$json = Json::fromEncoded(
149+
<<<JSON
150+
{
151+
"{$property}": {
152+
"sort-packages": true,
153+
"preferred-install": "dist",
154+
"foo": {
155+
"qux": "quux",
156+
"bar": {
157+
"qux": "quz",
158+
"baz": "qux"
159+
}
160+
}
161+
},
162+
"foo": {
163+
"qux": "quux",
164+
"bar": "baz"
165+
}
166+
}
167+
JSON
168+
);
169+
170+
$expected = Json::fromEncoded(
171+
<<<JSON
172+
{
173+
"{$property}": {
174+
"foo": {
175+
"bar": {
176+
"baz": "qux",
177+
"qux": "quz"
178+
},
179+
"qux": "quux"
180+
},
181+
"preferred-install": "dist",
182+
"sort-packages": true
183+
},
184+
"foo": {
185+
"qux": "quux",
186+
"bar": "baz"
187+
}
188+
}
189+
JSON
190+
);
191+
192+
$normalizer = new ConfigHashNormalizer();
193+
194+
$normalized = $normalizer->normalize($json);
195+
196+
self::assertJsonStringEqualsJsonStringNormalized($expected->encoded(), $normalized->encoded());
197+
}
198+
143199
/**
144200
* @return \Generator<array<string>>
145201
*/

0 commit comments

Comments
 (0)