diff --git a/src/Composer/Command/RequireCommand.php b/src/Composer/Command/RequireCommand.php index 415de9fe7..cf7c95664 100644 --- a/src/Composer/Command/RequireCommand.php +++ b/src/Composer/Command/RequireCommand.php @@ -226,6 +226,9 @@ EOT foreach ($requirements as $package => $version) { $composerDefinition[$requireKey][$package] = $version; unset($composerDefinition[$removeKey][$package]); + if (isset($composerDefinition[$removeKey]) && count($composerDefinition[$removeKey]) === 0) { + unset($composerDefinition[$removeKey]); + } } $this->json->write($composerDefinition); } @@ -341,6 +344,8 @@ EOT } } + $manipulator->removeMainKeyIfEmpty($removeKey); + file_put_contents($json->getPath(), $manipulator->getContents()); return true; diff --git a/src/Composer/Config/JsonConfigSource.php b/src/Composer/Config/JsonConfigSource.php index 36b0bc972..5c0c04a06 100644 --- a/src/Composer/Config/JsonConfigSource.php +++ b/src/Composer/Config/JsonConfigSource.php @@ -196,7 +196,8 @@ class JsonConfigSource implements ConfigSourceInterface { $this->manipulateJson('removeSubNode', $type, $name, function (&$config, $type, $name) { unset($config[$type][$name]); - + }); + $this->manipulateJson('removeMainKeyIfEmpty', $type, function (&$config, $type) { if (0 === count($config[$type])) { unset($config[$type]); } diff --git a/src/Composer/Json/JsonManipulator.php b/src/Composer/Json/JsonManipulator.php index b2b1be872..249116cfb 100644 --- a/src/Composer/Json/JsonManipulator.php +++ b/src/Composer/Json/JsonManipulator.php @@ -480,6 +480,21 @@ class JsonManipulator return false; } + public function removeMainKeyIfEmpty($key) + { + $decoded = JsonFile::parseJson($this->contents); + + if (!array_key_exists($key, $decoded)) { + return true; + } + + if (is_array($decoded[$key]) && count($decoded[$key]) === 0) { + return $this->removeMainKey($key); + } + + return false; + } + public function format($data, $depth = 0) { if (is_array($data)) { diff --git a/tests/Composer/Test/Config/Fixtures/removeLink/conflict-to-empty-after.json b/tests/Composer/Test/Config/Fixtures/removeLink/conflict-to-empty-after.json index 81fc11503..ba03df2ff 100644 --- a/tests/Composer/Test/Config/Fixtures/removeLink/conflict-to-empty-after.json +++ b/tests/Composer/Test/Config/Fixtures/removeLink/conflict-to-empty-after.json @@ -1,6 +1,4 @@ { "name": "my-vend/my-app", - "license": "MIT", - "conflict": { - } + "license": "MIT" } diff --git a/tests/Composer/Test/Config/Fixtures/removeLink/provide-to-empty-after.json b/tests/Composer/Test/Config/Fixtures/removeLink/provide-to-empty-after.json index 99b4224b1..ba03df2ff 100644 --- a/tests/Composer/Test/Config/Fixtures/removeLink/provide-to-empty-after.json +++ b/tests/Composer/Test/Config/Fixtures/removeLink/provide-to-empty-after.json @@ -1,6 +1,4 @@ { "name": "my-vend/my-app", - "license": "MIT", - "provide": { - } + "license": "MIT" } diff --git a/tests/Composer/Test/Config/Fixtures/removeLink/replace-to-empty-after.json b/tests/Composer/Test/Config/Fixtures/removeLink/replace-to-empty-after.json index 6430a49fc..ba03df2ff 100644 --- a/tests/Composer/Test/Config/Fixtures/removeLink/replace-to-empty-after.json +++ b/tests/Composer/Test/Config/Fixtures/removeLink/replace-to-empty-after.json @@ -1,6 +1,4 @@ { "name": "my-vend/my-app", - "license": "MIT", - "replace": { - } + "license": "MIT" } diff --git a/tests/Composer/Test/Config/Fixtures/removeLink/require-dev-to-empty-after.json b/tests/Composer/Test/Config/Fixtures/removeLink/require-dev-to-empty-after.json index 4058e5a20..ba03df2ff 100644 --- a/tests/Composer/Test/Config/Fixtures/removeLink/require-dev-to-empty-after.json +++ b/tests/Composer/Test/Config/Fixtures/removeLink/require-dev-to-empty-after.json @@ -1,6 +1,4 @@ { "name": "my-vend/my-app", - "license": "MIT", - "require-dev": { - } + "license": "MIT" } diff --git a/tests/Composer/Test/Config/Fixtures/removeLink/require-to-empty-after.json b/tests/Composer/Test/Config/Fixtures/removeLink/require-to-empty-after.json index 4f244ff96..ba03df2ff 100644 --- a/tests/Composer/Test/Config/Fixtures/removeLink/require-to-empty-after.json +++ b/tests/Composer/Test/Config/Fixtures/removeLink/require-to-empty-after.json @@ -1,6 +1,4 @@ { "name": "my-vend/my-app", - "license": "MIT", - "require": { - } + "license": "MIT" } diff --git a/tests/Composer/Test/Config/Fixtures/removeLink/suggest-to-empty-after.json b/tests/Composer/Test/Config/Fixtures/removeLink/suggest-to-empty-after.json index 21d79e2f4..ba03df2ff 100644 --- a/tests/Composer/Test/Config/Fixtures/removeLink/suggest-to-empty-after.json +++ b/tests/Composer/Test/Config/Fixtures/removeLink/suggest-to-empty-after.json @@ -1,6 +1,4 @@ { "name": "my-vend/my-app", - "license": "MIT", - "suggest": { - } + "license": "MIT" } diff --git a/tests/Composer/Test/Json/JsonManipulatorTest.php b/tests/Composer/Test/Json/JsonManipulatorTest.php index 118eb91c7..74243ca71 100644 --- a/tests/Composer/Test/Json/JsonManipulatorTest.php +++ b/tests/Composer/Test/Json/JsonManipulatorTest.php @@ -2437,6 +2437,48 @@ class JsonManipulatorTest extends TestCase ', $manipulator->getContents()); } + public function testRemoveMainKeyIfEmpty() + { + $manipulator = new JsonManipulator('{ + "repositories": [ + ], + "require": { + "package/a": "*", + "package/b": "*", + "package/c": "*" + }, + "foo": "bar", + "require-dev": { + } +}'); + + $this->assertTrue($manipulator->removeMainKeyIfEmpty('repositories')); + $this->assertEquals('{ + "require": { + "package/a": "*", + "package/b": "*", + "package/c": "*" + }, + "foo": "bar", + "require-dev": { + } +} +', $manipulator->getContents()); + + $this->assertFalse($manipulator->removeMainKeyIfEmpty('foo')); + $this->assertFalse($manipulator->removeMainKeyIfEmpty('require')); + $this->assertTrue($manipulator->removeMainKeyIfEmpty('require-dev')); + $this->assertEquals('{ + "require": { + "package/a": "*", + "package/b": "*", + "package/c": "*" + }, + "foo": "bar" +} +', $manipulator->getContents()); + } + public function testRemoveMainKeyRemovesKeyWhereValueIsNull() { $manipulator = new JsonManipulator(json_encode(array(