Skip to content

Commit 7bcf05e

Browse files
committed
Merge remote-tracking branch 'upstream/master'
* upstream/master: Feature/syntax check (nunomaduro#373) Fix display detail message without file (nunomaduro#404) Fix nunomaduro#401 (nunomaduro#402) Update doc (add phpunit upgrade command) (nunomaduro#399)
2 parents e7c8724 + 2617648 commit 7bcf05e

File tree

17 files changed

+231
-29
lines changed

17 files changed

+231
-29
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"justinrainbow/json-schema": "^5.1",
2121
"league/container": "^3.2",
2222
"object-calisthenics/phpcs-calisthenics-rules": "^3.7",
23+
"php-parallel-lint/php-parallel-lint": "^1.1",
2324
"phploc/phploc": "^5.0|^6.0",
2425
"psr/container": "^1.0",
2526
"sensiolabs/security-checker": "^6.0",

docs/insights/style.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,12 +179,20 @@ This sniff ensures the `PHP_SAPI` constant is used instead of `php_sapi_name()`.
179179

180180
**Insight Class**: `PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\SAPIUsageSniff`
181181

182-
## Syntax <Badge text="^1.0"/> <Badge text="Style" type="warn"/>
182+
## Syntax <Badge text="^1.0"/> <Badge text="Style" type="warn"/> <Badge text="Deprecated since 2.0" type="error"/>
183183

184184
This sniff ensures PHP believes the syntax is clean.
185185

186186
**Insight Class**: `PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\SyntaxSniff`
187187

188+
> Note: This sniff is deprecated, use insight below
189+
190+
## Syntax Check <Badge text="^2.0"/> <Badge text="Style" type="warn"/>
191+
192+
This Insight process lint on all PHP files via `php -l` using [PHP-Parallel-Lint](https://github.com/php-parallel-lint/PHP-Parallel-Lint).
193+
194+
**Insight Class**: `NunoMaduro\PhpInsights\Domain\Insights\SyntaxCheck`
195+
188196
## Trailing array comma <Badge text="^1.0"/> <Badge text="Style" type="warn"/>
189197

190198
This sniff enforces trailing commas in multi-line arrays and requires short array syntax `[]`.

src/Application/Console/Formatters/Console.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -586,8 +586,10 @@ private function formatFileLine(Details $detail, string $category, string $commo
586586
$formattedLink = $this->fileLinkFormatter->format($file, $detail->getLine());
587587
}
588588

589-
$color = $this->getCategoryColor($category);
590-
$detailString = sprintf('<fg=%s>%s</>', $color, $detailString);
589+
if ($detailString !== '') {
590+
$color = $this->getCategoryColor($category);
591+
$detailString = sprintf('<fg=%s>%s</>', $color, $detailString);
592+
}
591593

592594
if ($this->supportHyperLinks &&
593595
$formattedLink !== '' &&

src/Application/Injectors/InsightLoaders.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace NunoMaduro\PhpInsights\Application\Injectors;
66

77
use NunoMaduro\PhpInsights\Domain\InsightLoader\FixerLoader;
8+
use NunoMaduro\PhpInsights\Domain\InsightLoader\InsightLoader;
89
use NunoMaduro\PhpInsights\Domain\InsightLoader\SniffLoader;
910

1011
/**
@@ -20,6 +21,7 @@ final class InsightLoaders
2021
public function __invoke(): array
2122
{
2223
return [
24+
InsightLoader::class => static fn (): InsightLoader => new InsightLoader(),
2325
SniffLoader::class => static fn (): SniffLoader => new SniffLoader(),
2426
FixerLoader::class => static fn (): FixerLoader => new FixerLoader(),
2527
];
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NunoMaduro\PhpInsights\Domain\Contracts;
6+
7+
/**
8+
* @internal
9+
*/
10+
interface GlobalInsight extends Insight
11+
{
12+
/**
13+
* Launch Insight inspection.
14+
*/
15+
public function process(): void;
16+
}

src/Domain/Contracts/InsightLoader.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace NunoMaduro\PhpInsights\Domain\Contracts;
66

7+
use NunoMaduro\PhpInsights\Domain\Collector;
8+
79
/**
810
* @internal
911
*/
@@ -21,5 +23,5 @@ public function support(string $insightClass): bool;
2123
*
2224
* @param array<string, int|string|array> $config Related to $insightClass
2325
*/
24-
public function load(string $insightClass, string $dir, array $config): Insight;
26+
public function load(string $insightClass, string $dir, array $config, Collector $collector): Insight;
2527
}

src/Domain/FileFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,13 @@ final class FileFactory
2121
public function __construct()
2222
{
2323
$config = new Config([], false);
24+
// disable loading custom ruleset
25+
$config->restoreDefaults();
2426
$config->__set('tabWidth', 4);
2527
$config->__set('annotations', false);
2628
$config->__set('encoding', 'UTF-8');
29+
// Include only 1 sniff, they are register later
30+
$config->__set('sniffs', ['Generic.Files.LineEndings']);
2731

2832
$this->config = $config;
2933
$this->ruleset = new Ruleset($this->config);

src/Domain/InsightLoader/FixerLoader.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace NunoMaduro\PhpInsights\Domain\InsightLoader;
66

7+
use NunoMaduro\PhpInsights\Domain\Collector;
78
use NunoMaduro\PhpInsights\Domain\Contracts\Insight;
89
use NunoMaduro\PhpInsights\Domain\Contracts\InsightLoader;
910
use NunoMaduro\PhpInsights\Domain\Insights\FixerDecorator;
@@ -20,7 +21,7 @@ public function support(string $insightClass): bool
2021
return array_key_exists(FixerInterface::class, class_implements($insightClass));
2122
}
2223

23-
public function load(string $insightClass, string $dir, array $config): Insight
24+
public function load(string $insightClass, string $dir, array $config, Collector $collector): Insight
2425
{
2526
$fixer = new $insightClass();
2627

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NunoMaduro\PhpInsights\Domain\InsightLoader;
6+
7+
use NunoMaduro\PhpInsights\Domain\Collector;
8+
use NunoMaduro\PhpInsights\Domain\Contracts\Insight;
9+
use NunoMaduro\PhpInsights\Domain\Contracts\InsightLoader as LoaderContract;
10+
11+
/**
12+
* @internal
13+
*/
14+
final class InsightLoader implements LoaderContract
15+
{
16+
public function support(string $insightClass): bool
17+
{
18+
return array_key_exists(Insight::class, class_implements($insightClass));
19+
}
20+
21+
public function load(string $insightClass, string $dir, array $config, Collector $collector): Insight
22+
{
23+
return new $insightClass($collector, $config);
24+
}
25+
}

src/Domain/InsightLoader/SniffLoader.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace NunoMaduro\PhpInsights\Domain\InsightLoader;
66

7+
use NunoMaduro\PhpInsights\Domain\Collector;
78
use NunoMaduro\PhpInsights\Domain\Contracts\Insight;
89
use NunoMaduro\PhpInsights\Domain\Contracts\InsightLoader;
910
use NunoMaduro\PhpInsights\Domain\Insights\SniffDecorator;
@@ -19,7 +20,7 @@ public function support(string $insightClass): bool
1920
return array_key_exists(SniffContract::class, class_implements($insightClass));
2021
}
2122

22-
public function load(string $insightClass, string $dir, array $config): Insight
23+
public function load(string $insightClass, string $dir, array $config, Collector $collector): Insight
2324
{
2425
/** @var SniffContract $sniff */
2526
$sniff = new $insightClass();

src/Domain/Insights/InsightCollectionFactory.php

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,22 +59,13 @@ public function get(array $metrics, OutputInterface $consoleOutput): InsightColl
5959
$insightsClasses = [...$insightsClasses, ...$this->getInsights($metricClass)];
6060
}
6161

62-
$insightFactory = new InsightFactory($this->filesRepository, $insightsClasses, $this->config);
62+
$insightFactory = new InsightFactory($this->filesRepository, $insightsClasses, $this->config, $collector);
6363
$insightsForCollection = [];
6464

6565
foreach ($metrics as $metricClass) {
6666
$insightsForCollection[$metricClass] = array_map(
67-
function (string $insightClass) use ($insightFactory, $collector, $consoleOutput) {
68-
if (! array_key_exists(Insight::class, class_implements($insightClass))) {
69-
return $insightFactory->makeFrom(
70-
$insightClass,
71-
$consoleOutput
72-
);
73-
}
74-
75-
return new $insightClass($collector, $this->config->getConfigForInsight($insightClass));
76-
},
77-
$this->getInsights($metricClass),
67+
static fn (string $insightClass): Insight => $insightFactory->makeFrom($insightClass, $consoleOutput),
68+
$this->getInsights($metricClass)
7869
);
7970
}
8071

src/Domain/Insights/InsightFactory.php

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace NunoMaduro\PhpInsights\Domain\Insights;
66

77
use Exception;
8+
use NunoMaduro\PhpInsights\Domain\Collector;
89
use NunoMaduro\PhpInsights\Domain\Configuration;
910
use NunoMaduro\PhpInsights\Domain\Container;
1011
use NunoMaduro\PhpInsights\Domain\Contracts\Insight as InsightContract;
@@ -42,17 +43,20 @@ final class InsightFactory
4243

4344
private bool $ran = false;
4445

46+
private Collector $collector;
47+
4548
/**
4649
* Creates a new instance of Insight Factory.
4750
*
4851
* @param array<string> $insightsClasses
4952
*/
50-
public function __construct(FilesRepository $filesRepository, array $insightsClasses, Configuration $config)
53+
public function __construct(FilesRepository $filesRepository, array $insightsClasses, Configuration $config, Collector $collector)
5154
{
5255
$this->filesRepository = $filesRepository;
5356
$this->insightsClasses = $insightsClasses;
5457
$this->insightLoaders = Container::make()->get(InsightLoader::INSIGHT_LOADER_TAG);
5558
$this->config = $config;
59+
$this->collector = $collector;
5660
}
5761

5862
/**
@@ -114,7 +118,8 @@ private function loadInsights(array $insights): array
114118
$insightsAdded[] = $loader->load(
115119
$insight,
116120
$path,
117-
$this->config->getConfigForInsight($insight)
121+
$this->config->getConfigForInsight($insight),
122+
$this->collector
118123
);
119124
}
120125
}

src/Domain/Insights/SyntaxCheck.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace NunoMaduro\PhpInsights\Domain\Insights;
6+
7+
use NunoMaduro\PhpInsights\Domain\Contracts\GlobalInsight;
8+
use NunoMaduro\PhpInsights\Domain\Contracts\HasDetails;
9+
use NunoMaduro\PhpInsights\Domain\Details;
10+
use PHP_CodeSniffer\Config;
11+
use Symfony\Component\Process\Process;
12+
13+
/**
14+
* @internal
15+
*/
16+
final class SyntaxCheck extends Insight implements HasDetails, GlobalInsight
17+
{
18+
/** @var array<Details> */
19+
private array $details = [];
20+
21+
public function getTitle(): string
22+
{
23+
return 'Syntax Check';
24+
}
25+
26+
public function hasIssue(): bool
27+
{
28+
return count($this->details) > 0;
29+
}
30+
31+
public function getDetails(): array
32+
{
33+
return $this->details;
34+
}
35+
36+
public function process(): void
37+
{
38+
$phpPath = (string) Config::getExecutablePath('php');
39+
$filesToAnalyse = array_map(
40+
static fn (string $file): string => escapeshellarg($file),
41+
$this->filterFilesWithoutExcluded($this->collector->getFiles())
42+
);
43+
44+
$cmdLine = sprintf(
45+
'%s %s --no-colors --no-progress --json %s',
46+
escapeshellcmd($phpPath),
47+
escapeshellarg(dirname(__DIR__, 3) . '/vendor/bin/parallel-lint'),
48+
implode(' ', $filesToAnalyse)
49+
);
50+
51+
$process = Process::fromShellCommandline($cmdLine);
52+
$process->run();
53+
$output = json_decode($process->getOutput(), true);
54+
$errors = $output['results']['errors'] ?? [];
55+
56+
foreach ($errors as $error) {
57+
if (preg_match('/^.*error:(.*) in .* on line [\d]+/m', $error['message'], $matches) === 1) {
58+
$this->details[] = Details::make()
59+
->setFile($error['file'])
60+
->setLine($error['line'])
61+
->setMessage('PHP syntax error: ' . trim($matches[1]));
62+
}
63+
}
64+
}
65+
}

src/Domain/Metrics/Style/Style.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace NunoMaduro\PhpInsights\Domain\Metrics\Style;
66

77
use NunoMaduro\PhpInsights\Domain\Contracts\HasInsights;
8+
use NunoMaduro\PhpInsights\Domain\Insights\SyntaxCheck;
89
use PHP_CodeSniffer\Standards\Generic\Sniffs\Arrays\DisallowLongArraySyntaxSniff;
910
use PHP_CodeSniffer\Standards\Generic\Sniffs\Files\ByteOrderMarkSniff;
1011
use PHP_CodeSniffer\Standards\Generic\Sniffs\Files\LineEndingsSniff;
@@ -21,7 +22,6 @@
2122
use PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseKeywordSniff;
2223
use PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\LowerCaseTypeSniff;
2324
use PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\SAPIUsageSniff;
24-
use PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\SyntaxSniff;
2525
use PHP_CodeSniffer\Standards\Generic\Sniffs\VersionControl\GitMergeConflictSniff;
2626
use PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\ArbitraryParenthesesSpacingSniff;
2727
use PHP_CodeSniffer\Standards\Generic\Sniffs\WhiteSpace\DisallowTabIndentSniff;
@@ -97,6 +97,7 @@ final class Style implements HasInsights
9797
public function getInsights(): array
9898
{
9999
return [
100+
SyntaxCheck::class,
100101
ClosingTagSniff::class,
101102
EndFileNewlineSniff::class,
102103
SideEffectsSniff::class,
@@ -123,7 +124,6 @@ public function getInsights(): array
123124
LowerCaseKeywordSniff::class,
124125
LowerCaseTypeSniff::class,
125126
SAPIUsageSniff::class,
126-
SyntaxSniff::class,
127127
TrailingArrayCommaSniff::class,
128128
ArbitraryParenthesesSpacingSniff::class,
129129
DisallowTabIndentSniff::class,

src/Domain/Runner.php

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace NunoMaduro\PhpInsights\Domain;
66

77
use NunoMaduro\PhpInsights\Domain\Contracts\FileProcessor as FileProcessorContract;
8+
use NunoMaduro\PhpInsights\Domain\Contracts\GlobalInsight;
89
use NunoMaduro\PhpInsights\Domain\Contracts\Repositories\FilesRepository;
910
use Symfony\Component\Console\Helper\ProgressBar;
1011
use Symfony\Component\Console\Output\OutputInterface;
@@ -29,6 +30,9 @@ final class Runner
2930

3031
private FilesRepository $filesRepository;
3132

33+
/** @var array<\NunoMaduro\PhpInsights\Domain\Contracts\GlobalInsight|\NunoMaduro\PhpInsights\Domain\Contracts\Insight> */
34+
private array $globalInsights = [];
35+
3236
public function __construct(OutputInterface $output, FilesRepository $filesRepository)
3337
{
3438
$this->filesRepository = $filesRepository;
@@ -44,9 +48,14 @@ public function __construct(OutputInterface $output, FilesRepository $filesRepos
4448
*/
4549
public function addInsights(array $insights): void
4650
{
47-
/** @var FileProcessorContract $fileProcessor */
48-
foreach ($this->filesProcessors as $fileProcessor) {
49-
foreach ($insights as $insight) {
51+
foreach ($insights as $insight) {
52+
if ($insight instanceof GlobalInsight) {
53+
$this->globalInsights[] = $insight;
54+
continue;
55+
}
56+
57+
/** @var FileProcessorContract $fileProcessor */
58+
foreach ($this->filesProcessors as $fileProcessor) {
5059
if ($fileProcessor->support($insight)) {
5160
$fileProcessor->addChecker($insight);
5261
}
@@ -65,10 +74,21 @@ public function run(): void
6574
}
6675

6776
// Create progress bar
68-
$progressBar = $this->createProgressBar(count($files));
77+
$progressBar = $this->createProgressBar(count($files) + count($this->globalInsights));
6978
$progressBar->setMessage('');
7079
$progressBar->start();
7180

81+
/** @var GlobalInsight $insight */
82+
foreach ($this->globalInsights as $insight) {
83+
if ($this->output->isVerbose()) {
84+
$progressBar->setMessage(' - Global: ' . $insight->getTitle());
85+
$progressBar->display();
86+
}
87+
88+
$insight->process();
89+
$progressBar->advance();
90+
}
91+
7292
/** @var SplFileInfo $file */
7393
foreach ($files as $file) {
7494
// Output file name if verbose

0 commit comments

Comments
 (0)