Skip to content

Commit 7a09574

Browse files
authored
Add PhpdocSimplifyArrayKeyFixer
1 parent 9f8b790 commit 7a09574

File tree

11 files changed

+392
-11
lines changed

11 files changed

+392
-11
lines changed

.claude/settings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(make:*)"
5+
]
6+
}
7+
}

.github/workflows/format.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
runs-on: ubuntu-latest
1212

1313
steps:
14-
- uses: actions/checkout@v2
14+
- uses: actions/checkout@v4
1515
with:
1616
ref: ${{ github.head_ref }}
1717

@@ -30,7 +30,7 @@ jobs:
3030
runs-on: ubuntu-latest
3131

3232
steps:
33-
- uses: actions/checkout@v2
33+
- uses: actions/checkout@v4
3434
with:
3535
ref: ${{ github.head_ref }}
3636

.github/workflows/validate.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
on:
2+
pull_request:
3+
push:
4+
branches:
5+
- master
6+
7+
name: "Validate"
8+
9+
jobs:
10+
composer-validate:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: shivammathur/setup-php@v2
16+
with:
17+
php-version: "8.3"
18+
19+
- run: composer validate --strict
20+
21+
tests:
22+
runs-on: ubuntu-latest
23+
strategy:
24+
fail-fast: false
25+
matrix:
26+
php-version:
27+
- "7.4"
28+
- "8.0"
29+
- "8.1"
30+
- "8.2"
31+
- "8.3"
32+
- "8.4"
33+
dependencies:
34+
- lowest
35+
- highest
36+
steps:
37+
- uses: actions/checkout@v4
38+
39+
- uses: shivammathur/setup-php@v2
40+
with:
41+
php-version: ${{ matrix.php-version }}
42+
43+
- run: composer update --no-interaction --no-progress ${{ matrix.dependencies == 'lowest' && '--prefer-lowest' || '' }}
44+
45+
- run: vendor/bin/phpunit

.gitignore

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1+
.build/
12
.idea
2-
vendor
3-
composer.lock
43
.php-cs-fixer.cache
4+
composer.lock
5+
vendor

.php-cs-fixer.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
<?php declare(strict_types=1);
22

3-
use PhpCsFixer\Finder;
4-
use function MLL\PhpCsFixerConfig\risky;
5-
6-
$finder = Finder::create()
3+
$finder = PhpCsFixer\Finder::create()
74
->notPath('vendor')
85
->in(__DIR__)
96
->name('*.php')
107
->ignoreDotFiles(true)
118
->ignoreVCS(true);
129

13-
return risky($finder);
10+
return MLL\PhpCsFixerConfig\risky($finder);

Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.PHONY: it
2-
it: fix normalize ## Perform quality checks
2+
it: fix normalize test ## Perform quality checks
33

44
.PHONY: help
55
help: ## Displays this list of targets with descriptions
@@ -16,5 +16,10 @@ fix: ## Format PHP
1616
normalize: ## Normalize composer.json
1717
composer normalize
1818

19+
.PHONY: test
20+
test: ## Run PHPUnit tests
21+
mkdir --parent .build/phpunit
22+
vendor/bin/phpunit --cache-directory=.build/phpunit
23+
1924
vendor: composer.json ## Install dependencies through composer
2025
composer install

composer.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"kubawerlos/php-cs-fixer-custom-fixers": "^3.12"
2020
},
2121
"require-dev": {
22-
"ergebnis/composer-normalize": "^2.13"
22+
"ergebnis/composer-normalize": "^2.13",
23+
"phpunit/phpunit": "^9.6 || ^10.5 || ^11.0"
2324
},
2425
"autoload": {
2526
"psr-4": {
@@ -29,6 +30,11 @@
2930
"config.php"
3031
]
3132
},
33+
"autoload-dev": {
34+
"psr-4": {
35+
"MLL\\PhpCsFixerConfig\\Tests\\": "tests/"
36+
}
37+
},
3238
"config": {
3339
"allow-plugins": {
3440
"ergebnis/composer-normalize": true

config.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,18 @@ function config(Finder $finder, array $ruleOverrides = []): Config
8787
'less_and_greater' => false,
8888
],
8989

90+
Fixer\PhpdocSimplifyArrayKeyFixer::NAME => true,
91+
9092
PhpCsFixerCustomFixers\Fixer\ConstructorEmptyBracesFixer::name() => true,
9193
PhpCsFixerCustomFixers\Fixer\DeclareAfterOpeningTagFixer::name() => true, // Use native rule when added with https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/2062
9294
PhpCsFixerCustomFixers\Fixer\MultilinePromotedPropertiesFixer::name() => true,
9395
];
9496

9597
return (new Config())
9698
->registerCustomFixers(new PhpCsFixerCustomFixers\Fixers())
99+
->registerCustomFixers([
100+
new Fixer\PhpdocSimplifyArrayKeyFixer(),
101+
])
97102
->setFinder($finder)
98103
->setRules(array_merge($safeRules, $ruleOverrides));
99104
}

phpunit.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
5+
bootstrap="vendor/autoload.php"
6+
colors="true"
7+
>
8+
<testsuites>
9+
<testsuite name="Tests">
10+
<directory>tests</directory>
11+
</testsuite>
12+
</testsuites>
13+
</phpunit>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\PhpCsFixerConfig\Fixer;
4+
5+
use PhpCsFixer\AbstractPhpdocTypesFixer;
6+
use PhpCsFixer\FixerDefinition\CodeSample;
7+
use PhpCsFixer\FixerDefinition\FixerDefinition;
8+
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
9+
use PhpCsFixer\Preg;
10+
use PhpCsFixer\Tokenizer\Tokens;
11+
12+
/**
13+
* Simplifies PHPDoc definitions to array<T>, omitting explicit array-key defaults.
14+
*/
15+
final class PhpdocSimplifyArrayKeyFixer extends AbstractPhpdocTypesFixer
16+
{
17+
public const NAME = 'MLL/phpdoc_simplify_array_key';
18+
19+
public function getName(): string
20+
{
21+
return self::NAME;
22+
}
23+
24+
public function getDefinition(): FixerDefinitionInterface
25+
{
26+
return new FixerDefinition(
27+
'PHPDoc `array<T>` should be used instead of `array<array-key, T>`.',
28+
[
29+
new CodeSample(
30+
<<<'PHP'
31+
<?php
32+
/**
33+
* @param array<array-key, string> $x
34+
* @param array<string|int, Foo> $y
35+
* @return array<int|string, Foo>
36+
*/
37+
38+
PHP
39+
),
40+
]
41+
);
42+
}
43+
44+
public function isCandidate(Tokens $tokens): bool
45+
{
46+
return $tokens->isTokenKindFound(T_DOC_COMMENT);
47+
}
48+
49+
protected function normalize(string $type): string
50+
{
51+
// Match: array<array-key, T> or array<int|string, T> or array<string|int, T>
52+
// Uses [^\S\n]* (whitespace except newlines) to avoid matching multiline types,
53+
// which are not supported due to AbstractPhpdocTypesFixer requiring line count preservation.
54+
$ws = '[^\S\n]*'; // Whitespace except newlines
55+
56+
return Preg::replace(
57+
"/\\barray<{$ws}(?:array-key|int{$ws}\\|{$ws}string|string{$ws}\\|{$ws}int){$ws},{$ws}/",
58+
'array<',
59+
$type
60+
);
61+
}
62+
}

0 commit comments

Comments
 (0)