From 8534ffdf89a594b7a55fe3366a070b004942b9b0 Mon Sep 17 00:00:00 2001
From: jurgenhaas <juergen@paragon-es.de>
Date: Fri, 3 Jul 2020 15:41:59 +0200
Subject: [PATCH] Improve settings merge

---
 src/Handler.php     | 148 +++++++++++++++++++++++---------------------
 src/NestedArray.php |  52 ++++++++++++++++
 2 files changed, 130 insertions(+), 70 deletions(-)
 create mode 100644 src/NestedArray.php

diff --git a/src/Handler.php b/src/Handler.php
index 13e9eb8..2fe7d75 100644
--- a/src/Handler.php
+++ b/src/Handler.php
@@ -46,19 +46,17 @@ class Handler {
    */
   public function configureComposerJson() {
     $fs = new Filesystem();
-    $options = $this->getOptions();
     $projectRoot = getcwd();
 
     // Append DrupalSpoon related components to composer.json.
-    $content = [];
+    $content = $this->defaultSettings();
     foreach (['composer.disabled.json', 'composer.json'] as $file) {
       $jsonFile = new JsonFile($projectRoot . '/' . $file);
       if ($jsonFile->exists()) {
-        $content = array_merge_recursive($content, $jsonFile->read());
+        $content = NestedArray::mergeDeep($content, $jsonFile->read());
         $fs->remove($projectRoot . '/' . $file);
       }
     }
-    $content = array_merge_recursive($content, $options);
     $jsonFile = new JsonFile($projectRoot . '/composer.json');
     $jsonFile->write($content);
 
@@ -98,80 +96,90 @@ class Handler {
   }
 
   /**
-   * Retrieve configuration for this package.
+   * Get default settings for DrupalSpoons.
    *
    * @return array
-   *   The settings from the extra configuration.
+   *   The default settings.
    */
-  protected function getOptions(): array {
-    $extra = $this->composer->getPackage()->getExtra() + ['drupalspoons' => []];
-    return $extra['drupalspoons'] + [
-        'repositories' => [
-          [
-            'type' => 'composer',
-            'url' => 'https://packages.drupal.org/8',
-          ],
-        ],
-        'require-dev' => [
-          'lakedrops/drupal-spoons' => 'dev-master',
-          'composer/installers' => '^1',
-          'drupal/core-composer-scaffold' => '^8.8',
-          'cweagans/composer-patches' => '~1.0',
-          'drupal/core-recommended' => '^8.8',
-          'drupal/core-dev' => '^8.8',
-          'drush/drush' => '^10',
-          'mglaman/phpstan-drupal' => '^0.12',
-          'phpstan/phpstan-deprecation-rules' => '^0.12',
-          'php-parallel-lint/php-parallel-lint' => '^1.2',
-          'zaporylie/composer-drupal-optimizations' => '^1.0',
-        ],
-        'scripts' => [
-          'si' => 'drush si -v --db-url=${SIMPLETEST_DB:-mysql://root:password@mariadb/db}',
-          'phpcs' => 'phpcs --runtime-set ignore_warnings_on_exit 1 --runtime-set ignore_errors_on_exit 1 web/modules/custom',
-          'lint' => 'parallel-lint --exclude web --exclude vendor .',
-          'webserver' => 'cd web && php -S 0.0.0.0:8888 .ht.router.php',
-          'chromedriver' => 'chromedriver --port=9515 --verbose --whitelisted-ips --log-path=/tmp/chromedriver.log --no-sandbox',
-          'unit' => 'phpunit --verbose web/modules/custom',
-          'phpstan' => 'phpstan analyse web/modules/custom',
-          'stylelint' => 'yarn --silent --cwd web/core stylelint --formatter verbose --config ./.stylelintrc.json ../modules/custom/**/*.css',
-          'eslint' => 'yarn --silent --cwd web/core eslint -c ./.eslintrc.json ../modules/custom',
+  protected function defaultSettings(): array {
+    return [
+      'name' => '',
+      'type' => '',
+      'description' => '',
+      'keywords' => [],
+      'license' => 'GPL-2.0+',
+      'homepage' => '',
+      'authors' => [],
+      'minimum-stability' => 'dev',
+      'support' => [],
+      'repositories' => [
+        [
+          'type' => 'composer',
+          'url' => 'https://packages.drupal.org/8',
         ],
-        'config' => [
-          'process-timeout' => 36000,
-        ],
-        'extra' => [
-          'installer-paths' => [
-            'web/core' => [
-              0 => 'type:drupal-core',
-            ],
-            'web/libraries/{$name}' => [
-              0 => 'type:drupal-library',
-            ],
-            'web/modules/contrib/{$name}' => [
-              0 => 'type:drupal-module',
-            ],
-            'web/profiles/{$name}' => [
-              0 => 'type:drupal-profile',
-            ],
-            'web/themes/{$name}' => [
-              0 => 'type:drupal-theme',
-            ],
-            'drush/{$name}' => [
-              0 => 'type:drupal-drush',
-            ],
+      ],
+      'require' => [],
+      'suggest' => [],
+      'require-dev' => [
+        'lakedrops/drupal-spoons' => 'dev-master',
+        'composer/installers' => '^1',
+        'drupal/core-composer-scaffold' => '^8.8',
+        'cweagans/composer-patches' => '~1.0',
+        'drupal/core-recommended' => '^8.8',
+        'drupal/core-dev' => '^8.8',
+        'drush/drush' => '^10',
+        'mglaman/phpstan-drupal' => '^0.12',
+        'phpstan/phpstan-deprecation-rules' => '^0.12',
+        'php-parallel-lint/php-parallel-lint' => '^1.2',
+        'zaporylie/composer-drupal-optimizations' => '^1.0',
+      ],
+      'scripts' => [
+        'si' => 'drush si -v --db-url=${SIMPLETEST_DB:-mysql://root:password@mariadb/db}',
+        'phpcs' => 'phpcs --runtime-set ignore_warnings_on_exit 1 --runtime-set ignore_errors_on_exit 1 web/modules/custom',
+        'lint' => 'parallel-lint --exclude web --exclude vendor .',
+        'webserver' => 'cd web && php -S 0.0.0.0:8888 .ht.router.php',
+        'chromedriver' => 'chromedriver --port=9515 --verbose --whitelisted-ips --log-path=/tmp/chromedriver.log --no-sandbox',
+        'unit' => 'phpunit --verbose web/modules/custom',
+        'phpstan' => 'phpstan analyse web/modules/custom',
+        'stylelint' => 'yarn --silent --cwd web/core stylelint --formatter verbose --config ./.stylelintrc.json ../modules/custom/**/*.css',
+        'eslint' => 'yarn --silent --cwd web/core eslint -c ./.eslintrc.json ../modules/custom',
+      ],
+      'config' => [
+        'process-timeout' => 36000,
+      ],
+      'extra' => [
+        'installer-paths' => [
+          'web/core' => [
+            0 => 'type:drupal-core',
+          ],
+          'web/libraries/{$name}' => [
+            0 => 'type:drupal-library',
+          ],
+          'web/modules/contrib/{$name}' => [
+            0 => 'type:drupal-module',
           ],
-          'drupal-scaffold' => [
-            'locations' => [
-              'web-root' => 'web/',
-            ],
+          'web/profiles/{$name}' => [
+            0 => 'type:drupal-profile',
           ],
-          'drush' => [
-            'services' => [
-              'drush.services.yml' => '^9 || ^10',
-            ],
+          'web/themes/{$name}' => [
+            0 => 'type:drupal-theme',
+          ],
+          'drush/{$name}' => [
+            0 => 'type:drupal-drush',
+          ],
+        ],
+        'drupal-scaffold' => [
+          'locations' => [
+            'web-root' => 'web/',
+          ],
+        ],
+        'drush' => [
+          'services' => [
+            'drush.services.yml' => '^9 || ^10',
           ],
         ],
-      ];
+      ],
+    ];
   }
 
 }
diff --git a/src/NestedArray.php b/src/NestedArray.php
new file mode 100644
index 0000000..e7c126c
--- /dev/null
+++ b/src/NestedArray.php
@@ -0,0 +1,52 @@
+<?php
+
+namespace LakeDrops\DrupalSpoons;
+
+/**
+ * Class NestedArray.
+ *
+ * @package LakeDrops\DrupalSpoons
+ */
+class NestedArray {
+
+  /**
+   * Deeply merges arrays. Borrowed from drupal.org/project/core.
+   *
+   * @return array
+   *   The merged array.
+   */
+  public static function mergeDeep(): array {
+    return self::mergeDeepArray(func_get_args());
+  }
+
+  /**
+   * Deeply merges arrays. Borrowed from drupal.org/project/core.
+   *
+   * @param array $arrays
+   *   An array of array that will be merged.
+   * @param bool $preserve_integer_keys
+   *   Whether to preserve integer keys.
+   *
+   * @return array
+   *   The merged array.
+   */
+  public static function mergeDeepArray(array $arrays, $preserve_integer_keys = FALSE): array {
+    $result = [];
+    foreach ($arrays as $array) {
+      foreach ($array as $key => $value) {
+        if (is_int($key) && !$preserve_integer_keys) {
+          $result[] = $value;
+        }
+        /** @noinspection NotOptimalIfConditionsInspection */
+        elseif (isset($result[$key]) && is_array($result[$key]) && is_array($value)) {
+          $result[$key] = self::mergeDeepArray([$result[$key], $value], $preserve_integer_keys);
+        }
+        else {
+          $result[$key] = $value;
+        }
+      }
+    }
+    return $result;
+  }
+
+}
-- 
GitLab