Skip to content

Commit 6f113c1

Browse files
Feature allow configuration extension from a different base file (#373)
* feat: allow configuration extension from a different base file * fix: typo * fix: lint issues * fix: static analyses issue * fix: another lint issue * feat: use array_replace_recursively and add more tests * fix: lint issue * Update ConfigurationJsonRepository.php --------- Co-authored-by: Taylor Otwell <taylor@laravel.com>
1 parent 579cc7a commit 6f113c1

File tree

7 files changed

+93
-1
lines changed

7 files changed

+93
-1
lines changed

app/Repositories/ConfigurationJsonRepository.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,13 @@ public function preset()
7777
protected function get()
7878
{
7979
if (! is_null($this->path) && $this->fileExists((string) $this->path)) {
80-
return tap(json_decode(file_get_contents($this->path), true), function ($configuration) {
80+
$baseConfig = json_decode(file_get_contents($this->path), true);
81+
82+
if (isset($baseConfig['extend'])) {
83+
$baseConfig = $this->resolveExtend($baseConfig);
84+
}
85+
86+
return tap($baseConfig, function ($configuration) {
8187
if (! is_array($configuration)) {
8288
abort(1, sprintf('The configuration file [%s] is not valid JSON.', $this->path));
8389
}
@@ -99,4 +105,23 @@ protected function fileExists(string $path)
99105
default => file_exists($path)
100106
};
101107
}
108+
109+
/**
110+
* Resolve the file to extend.
111+
*
112+
* @param array<string, array<int, string>|string> $configuration
113+
* @return array<string, array<int, string>|string>
114+
*/
115+
private function resolveExtend(array $configuration)
116+
{
117+
$path = realpath(dirname($this->path).DIRECTORY_SEPARATOR.$configuration['extend']);
118+
119+
$extended = json_decode(file_get_contents($path), true);
120+
121+
if (isset($extended['extend'])) {
122+
throw new \LogicException('Pint configuration cannot extend from more than 1 file.');
123+
}
124+
125+
return array_replace_recursive($extended, $configuration);
126+
}
102127
}

tests/Fixtures/extend/base.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"preset": "psr12",
3+
"rules": {
4+
"array_push": true,
5+
"backtick_to_shell_exec": true,
6+
"date_time_immutable": true,
7+
"final_internal_class": true,
8+
"final_public_method_for_abstract_class": true,
9+
"fully_qualified_strict_types": true,
10+
"global_namespace_import": {
11+
"import_classes": true,
12+
"import_constants": true
13+
}
14+
}
15+
}

tests/Fixtures/extend/pint.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"extend": "./base.json",
3+
"preset": "laravel",
4+
"rules": {
5+
"declare_strict_types": true,
6+
"lowercase_keywords": true,
7+
"lowercase_static_reference": true,
8+
"final_class": true,
9+
"fully_qualified_strict_types": false,
10+
"global_namespace_import": {
11+
"import_functions": true
12+
}
13+
}
14+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extend": "./config.json"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"preset": "laravel"
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extend": "./base.json"
3+
}

tests/Unit/Repositories/ConfigurationJsonRepositoryTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,32 @@
4646

4747
expect($repository->preset())->toBe('laravel');
4848
});
49+
50+
it('properly extend the base config file', function () {
51+
$repository = new ConfigurationJsonRepository(dirname(__DIR__, 2).'/Fixtures/extend/pint.json', null);
52+
53+
expect($repository->preset())->toBe('laravel')
54+
->and($repository->rules())->toBe([
55+
'array_push' => true,
56+
'backtick_to_shell_exec' => true,
57+
'date_time_immutable' => true,
58+
'final_internal_class' => true,
59+
'final_public_method_for_abstract_class' => true,
60+
'fully_qualified_strict_types' => false,
61+
'global_namespace_import' => [
62+
'import_classes' => true,
63+
'import_constants' => true,
64+
'import_functions' => true,
65+
],
66+
'declare_strict_types' => true,
67+
'lowercase_keywords' => true,
68+
'lowercase_static_reference' => true,
69+
'final_class' => true,
70+
]);
71+
});
72+
73+
it('throw an error if the extended configuration also has an extend', function () {
74+
$repository = new ConfigurationJsonRepository(dirname(__DIR__, 2).'/Fixtures/extend_recursive/pint.json', null);
75+
76+
$repository->finder();
77+
})->throws(LogicException::class);

0 commit comments

Comments
 (0)