Skip to content

Commit 2dd189a

Browse files
committed
feat: Add custom DeclareStrictTypesFixer to handle LK copyrights comment
1 parent 2dae149 commit 2dd189a

File tree

8 files changed

+192
-14
lines changed

8 files changed

+192
-14
lines changed

Dockerfile

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,22 @@ RUN cd ~ \
2222
&& php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer \
2323
&& composer
2424

25-
RUN composer global config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
26-
RUN composer global require -W symplify/coding-standard:^12.0 symplify/easy-coding-standard:^12.0 friendsofphp/php-cs-fixer:^3.41 kubawerlos/php-cs-fixer-custom-fixers:^3.17 squizlabs/php_codesniffer:^3.8 slevomat/coding-standard:^8.14
27-
2825
ENV PATH="~/.composer/vendor/bin:${PATH}"
2926

3027
RUN mkdir -p /app
3128
RUN mkdir -p /codebase
32-
COPY ecs.php /app
29+
COPY ./src /app
30+
31+
RUN composer global config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
32+
RUN composer global config repositories.justcoded/php-code-analysis-tool path /app
33+
RUN composer global require -W \
34+
justcoded/php-code-analysis-tool:* \
35+
symplify/coding-standard:^12.0 \
36+
symplify/easy-coding-standard:^12.0 \
37+
friendsofphp/php-cs-fixer:^3.41 \
38+
kubawerlos/php-cs-fixer-custom-fixers:^3.17 \
39+
squizlabs/php_codesniffer:^3.8 \
40+
slevomat/coding-standard:^8.14
3341

3442
WORKDIR /codebase
3543

bin/code.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
.PHONY: code.check code.check.dirty code.fix code.fix.dirty code.check.diff code.fix.diff
22

3-
version ?= 0.3.0
3+
version ?= 0.4.1
44
branch ?= develop
55

66
ECS_IMAGE := hub.jcdev.net:24000/php-code-analysis-tool:${version}

composer.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
"require": {
66
"symplify/coding-standard": "^12.0",
77
"symplify/easy-coding-standard": "^12.0",
8-
"friendsofphp/php-cs-fixer": "^3.26",
9-
"kubawerlos/php-cs-fixer-custom-fixers": "^3.16",
10-
"squizlabs/php_codesniffer": "^3.7",
11-
"slevomat/coding-standard": "^8.13"
8+
"friendsofphp/php-cs-fixer": "^3.41",
9+
"kubawerlos/php-cs-fixer-custom-fixers": "^3.17",
10+
"squizlabs/php_codesniffer": "^3.8",
11+
"slevomat/coding-standard": "^8.14"
1212
},
1313
"license": "MIT",
1414
"authors": [
@@ -17,12 +17,17 @@
1717
"email": "igoshin18@gmail.com"
1818
}
1919
],
20+
"autoload": {
21+
"psr-4": {
22+
"JustCoded\\PhpCodeAnalysisTool\\": "/src"
23+
}
24+
},
2025
"minimum-stability": "dev",
2126
"prefer-stable": true,
2227
"config": {
2328
"allow-plugins": {
2429
"dealerdirect/phpcodesniffer-composer-installer": true
2530
}
2631
},
27-
"version": "v0.2.1"
32+
"version": "v0.4.0"
2833
}

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace JustCoded\PhpCodeAnalysisTool\Fixers;
6+
7+
use PhpCsFixer\AbstractFixer;
8+
use PhpCsFixer\DocBlock\DocBlock;
9+
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
10+
use PhpCsFixer\FixerDefinition\CodeSample;
11+
use PhpCsFixer\FixerDefinition\FixerDefinition;
12+
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
13+
use PhpCsFixer\Tokenizer\Token;
14+
use PhpCsFixer\Tokenizer\Tokens;
15+
use SplFileInfo;
16+
17+
final class DeclareStrictTypesFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
18+
{
19+
public function getDefinition(): FixerDefinitionInterface
20+
{
21+
return new FixerDefinition(
22+
'Force strict types declaration in all files. Requires PHP >= 7.0.',
23+
[
24+
new CodeSample(
25+
"<?php\n",
26+
),
27+
],
28+
null,
29+
'Forcing strict types will stop non strict code from working.',
30+
);
31+
}
32+
33+
public function getPriority(): int
34+
{
35+
return 2;
36+
}
37+
38+
public function isCandidate(Tokens $tokens): bool
39+
{
40+
return isset($tokens[0]) && $tokens[0]->isGivenKind(T_OPEN_TAG);
41+
}
42+
43+
public function isRisky(): bool
44+
{
45+
return true;
46+
}
47+
48+
protected function applyFix(SplFileInfo $file, Tokens $tokens): void
49+
{
50+
// check if the declaration is already done
51+
$searchIndex = $tokens->getNextMeaningfulToken(0);
52+
if (null === $searchIndex) {
53+
$this->insertSequence($tokens); // declaration not found, insert one
54+
55+
return;
56+
}
57+
58+
$sequenceLocation = $tokens->findSequence([[T_DECLARE, 'declare'],
59+
'(',
60+
[T_STRING, 'strict_types'],
61+
'=',
62+
[T_LNUMBER],
63+
')'], $searchIndex, null, false);
64+
if (null === $sequenceLocation) {
65+
$this->insertSequence($tokens); // declaration not found, insert one
66+
67+
return;
68+
}
69+
70+
$this->fixStrictTypesCasingAndValue($tokens, $sequenceLocation);
71+
}
72+
73+
/**
74+
* @param array<int, Token> $sequence
75+
*/
76+
private function fixStrictTypesCasingAndValue(Tokens $tokens, array $sequence): void
77+
{
78+
/** @var int $index */
79+
/** @var Token $token */
80+
foreach ($sequence as $index => $token) {
81+
if ($token->isGivenKind(T_STRING)) {
82+
$tokens[$index] = new Token([T_STRING, strtolower($token->getContent())]);
83+
84+
continue;
85+
}
86+
if ($token->isGivenKind(T_LNUMBER)) {
87+
$tokens[$index] = new Token([T_LNUMBER, '1']);
88+
89+
break;
90+
}
91+
}
92+
}
93+
94+
private function insertSequence(Tokens $tokens): void
95+
{
96+
$sequence = [
97+
new Token([T_DECLARE, 'declare']),
98+
new Token('('),
99+
new Token([T_STRING, 'strict_types']),
100+
new Token('='),
101+
new Token([T_LNUMBER, '1']),
102+
new Token(')'),
103+
new Token(';'),
104+
];
105+
$endIndex = count($sequence);
106+
107+
$insertIndex = 1;
108+
109+
foreach ($tokens as $index => $token) {
110+
if (!$token->isGivenKind(T_DOC_COMMENT)) {
111+
continue;
112+
}
113+
114+
$doc = new DocBlock($token->getContent());
115+
116+
if (!count($doc->getAnnotationsOfType(['copyright']))) {
117+
break;
118+
}
119+
120+
$insertIndex = $tokens->getNextMeaningfulToken($index);
121+
122+
if (!$insertIndex) {
123+
return;
124+
}
125+
}
126+
127+
$tokens->insertAt($insertIndex, $sequence);
128+
129+
// start index of the sequence is always 1 here, 0 is always open tag
130+
// transform "<?php\n" to "<?php " if needed
131+
if (str_contains($tokens[0]->getContent(), "\n")) {
132+
$tokens[0] = new Token([$tokens[0]->getId(), trim($tokens[0]->getContent()) . ' ']);
133+
}
134+
135+
if ($endIndex === count($tokens) - 1) {
136+
return; // no more tokens after sequence, single_blank_line_at_eof might add a line
137+
}
138+
139+
$lineEnding = $this->whitespacesConfig->getLineEnding();
140+
if (!$tokens[1 + $endIndex]->isWhitespace()) {
141+
$tokens->insertAt($insertIndex + $endIndex, new Token([T_WHITESPACE, $lineEnding]));
142+
143+
return;
144+
}
145+
146+
$content = $tokens[$insertIndex + $endIndex]->getContent();
147+
$tokens[$insertIndex + $endIndex] = new Token([T_WHITESPACE, $lineEnding . ltrim($content, " \t")]);
148+
}
149+
}

src/composer.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "justcoded/php-code-analysis-tool",
3+
"description": "Automatically check and fix PHP code. We need composer.json to install dependencies and allow IDE to help us with maintaining ecs.php",
4+
"type": "package",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "Roman Ihoshyn",
9+
"email": "igoshin18@gmail.com"
10+
}
11+
],
12+
"autoload": {
13+
"psr-4": {
14+
"JustCoded\\PhpCodeAnalysisTool\\": "./"
15+
}
16+
},
17+
"version": "v0.4.0"
18+
}

ecs.php renamed to src/ecs.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
declare(strict_types=1);
44

5+
use JustCoded\PhpCodeAnalysisTool\Fixers\DeclareStrictTypesFixer;
56
use PhpCsFixer\Fixer\Alias\NoAliasFunctionsFixer;
67
use PhpCsFixer\Fixer\Alias\NoAliasLanguageConstructCallFixer;
78
use PhpCsFixer\Fixer\Alias\NoMixedEchoPrintFixer;
@@ -84,7 +85,6 @@
8485
use PhpCsFixer\Fixer\Semicolon\MultilineWhitespaceBeforeSemicolonsFixer;
8586
use PhpCsFixer\Fixer\Semicolon\NoEmptyStatementFixer;
8687
use PhpCsFixer\Fixer\Semicolon\NoSinglelineWhitespaceBeforeSemicolonsFixer;
87-
use PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer;
8888
use PhpCsFixer\Fixer\StringNotation\ExplicitStringVariableFixer;
8989
use PhpCsFixer\Fixer\StringNotation\HeredocToNowdocFixer;
9090
use PhpCsFixer\Fixer\StringNotation\NoBinaryStringFixer;

test/.gitignore

Lines changed: 0 additions & 2 deletions
This file was deleted.

0 commit comments

Comments
 (0)