Skip to content

Commit a7bd265

Browse files
Improve CI checks (#34)
* Add phpstan lvl 8 to CI + fix code to pass * Upgrade to phpunit 10.5 * Fixes after review
1 parent 2881cb5 commit a7bd265

17 files changed

+157
-89
lines changed

.github/workflows/ci.yaml

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
php: 8.2
3131
deps: high
3232
- symfony-version: 7.1
33-
php: 8.2
33+
php: 8.3
3434
deps: high
3535
steps:
3636
- uses: actions/checkout@v3
@@ -53,7 +53,7 @@ jobs:
5353

5454
- name: Run tests
5555
run: |
56-
./vendor/bin/simple-phpunit
56+
./vendor/bin/phpunit
5757
5858
php-cs-fixer:
5959
name: PHP CS Fixer
@@ -71,3 +71,22 @@ jobs:
7171
- name: Run PHP-CS-Fixer
7272
run:
7373
php-cs-fixer fix --dry-run --diff
74+
75+
phpstan:
76+
name: PHPStan
77+
runs-on: ubuntu-latest
78+
steps:
79+
- name: Checkout code
80+
uses: actions/checkout@v3
81+
82+
- name: Setup PHP
83+
uses: shivammathur/setup-php@v2
84+
with:
85+
php-version: 8.2
86+
tools: phpstan
87+
88+
- name: Install Composer dependencies
89+
run: composer install --no-progress --prefer-dist --optimize-autoloader
90+
91+
- name: Run PHPStan
92+
run: vendor/bin/phpstan analyse

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/vendor/
22
composer.lock
33
.php-cs-fixer.cache
4-
.phpunit.result.cache
4+
.phpunit.cache/
55
/tests/fixtures/var

composer.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@
2121
"require-dev": {
2222
"symfony/filesystem": "^6.3|^7.0",
2323
"symfony/framework-bundle": "^6.3|^7.0",
24-
"symfony/phpunit-bridge": "^6.3|^7.0",
25-
"phpstan/phpstan": "1.11.x-dev"
24+
"phpstan/phpstan": "^1",
25+
"phpstan/phpstan-symfony": "^1.3",
26+
"phpunit/phpunit": "^10.5"
2627
},
2728
"autoload": {
2829
"psr-4": {

phpstan.dist.neon

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
parameters:
2+
level: 8
3+
paths:
4+
- src/
5+
- tests/
6+
includes:
7+
- vendor/phpstan/phpstan-symfony/extension.neon

phpunit.xml.dist

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,26 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
32
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
43
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5-
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
4+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
65
backupGlobals="false"
76
colors="true"
87
bootstrap="vendor/autoload.php"
9-
convertDeprecationsToExceptions="false"
10-
>
11-
<php>
12-
<ini name="display_errors" value="1" />
13-
<ini name="error_reporting" value="-1" />
14-
<server name="KERNEL_CLASS" value="Sensiolabs\TypeScriptBundle\Tests\fixtures\TypeScriptTestKernel"/>
15-
<server name="APP_ENV" value="test" force="true" />
16-
<server name="SHELL_VERBOSITY" value="-1" />
17-
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
18-
<server name="SYMFONY_PHPUNIT_VERSION" value="9.5" />
19-
</php>
20-
21-
<testsuites>
22-
<testsuite name="Bundle Test Suite">
23-
<directory>tests</directory>
24-
</testsuite>
25-
</testsuites>
26-
27-
<coverage processUncoveredFiles="true">
28-
<include>
29-
<directory suffix=".php">src</directory>
30-
</include>
31-
</coverage>
32-
33-
<listeners>
34-
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
35-
</listeners>
8+
cacheDirectory=".phpunit.cache">
9+
<php>
10+
<ini name="display_errors" value="1"/>
11+
<ini name="error_reporting" value="-1"/>
12+
<server name="KERNEL_CLASS" value="Sensiolabs\TypeScriptBundle\Tests\fixtures\TypeScriptTestKernel"/>
13+
<server name="APP_ENV" value="test" force="true"/>
14+
<server name="SHELL_VERBOSITY" value="-1"/>
15+
</php>
16+
<testsuites>
17+
<testsuite name="Bundle Test Suite">
18+
<directory>tests</directory>
19+
</testsuite>
20+
</testsuites>
21+
<source>
22+
<include>
23+
<directory suffix=".php">src</directory>
24+
</include>
25+
</source>
3626
</phpunit>

src/AssetMapper/TypeScriptCompiler.php

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ class TypeScriptCompiler implements AssetCompilerInterface
1111
{
1212
private Filesystem $fileSystem;
1313

14+
/**
15+
* @param list<string> $typeScriptFilesPaths
16+
*/
1417
public function __construct(
1518
private readonly array $typeScriptFilesPaths,
1619
private readonly string $jsPathDirectory,
@@ -21,34 +24,53 @@ public function __construct(
2124

2225
public function supports(MappedAsset $asset): bool
2326
{
24-
if (!str_ends_with($asset->sourcePath, '.ts')) {
27+
$realSourcePath = realpath($asset->sourcePath);
28+
if (false === $realSourcePath) {
29+
return false;
30+
}
31+
if (!str_ends_with($realSourcePath, '.ts')) {
2532
return false;
2633
}
2734
foreach ($this->typeScriptFilesPaths as $path) {
35+
$realTypeScriptPath = realpath($path);
36+
if (false === $realTypeScriptPath) {
37+
throw new \Exception(sprintf('The TypeScript directory "%s" does not exist', $path));
38+
}
2839
// If the asset matches one of the TypeScript files source paths
29-
if (realpath($asset->sourcePath) === realpath($path)) {
40+
if ($realSourcePath === $realTypeScriptPath) {
3041
return true;
3142
}
3243
// If the asset is in a directory (or subdirectory) of one of the TypeScript directory source paths
33-
if (is_dir($path) && !str_starts_with($this->fileSystem->makePathRelative(realpath($asset->sourcePath), realpath($path)), '../')) {
44+
if (is_dir($realTypeScriptPath) && !str_starts_with($this->fileSystem->makePathRelative($realSourcePath, $realTypeScriptPath), '../')) {
3445
return true;
3546
}
3647
}
3748

38-
throw new \Exception(sprintf('The TypeScript file "%s" is not in the TypeScript files paths. Check the asset path or your "sensiolabs_typescript.source_dir" in your config', $asset->sourcePath));
49+
throw new \Exception(sprintf('The TypeScript file "%s" is not in the TypeScript files paths. Check the asset path or your "sensiolabs_typescript.source_dir" in your config', $realSourcePath));
3950
}
4051

4152
public function compile(string $content, MappedAsset $asset, AssetMapperInterface $assetMapper): string
4253
{
54+
$realSourcePath = realpath($asset->sourcePath);
55+
if (false === $realSourcePath) {
56+
throw new \Exception(sprintf('The TypeScript file "%s" does not exist', $asset->sourcePath));
57+
}
4358
foreach ($this->typeScriptFilesPaths as $typeScriptFilesPath) {
44-
if (str_starts_with(realpath($asset->sourcePath), realpath($typeScriptFilesPath))) {
45-
$fileName = basename($asset->sourcePath, '.ts');
46-
$subPath = trim($this->fileSystem->makePathRelative(\dirname($asset->sourcePath), $this->projectRootDir), '/');
59+
$realTypeScriptPath = realpath($typeScriptFilesPath);
60+
if (false === $realTypeScriptPath) {
61+
throw new \Exception(sprintf('The TypeScript directory "%s" does not exist', $typeScriptFilesPath));
62+
}
63+
if (str_starts_with($realSourcePath, $realTypeScriptPath)) {
64+
$fileName = basename($realSourcePath, '.ts');
65+
$subPath = trim($this->fileSystem->makePathRelative(\dirname($realSourcePath), $this->projectRootDir), '/');
4766
$jsFile = $this->jsPathDirectory.'/'.$subPath.'/'.$fileName.'.js';
4867
break;
4968
}
5069
}
5170

71+
if (!isset($jsFile)) {
72+
throw new \Exception(sprintf('The TypeScript file "%s" is not in the TypeScript files paths. Check the asset path or your "sensiolabs_typescript.source_dir" in your config', $asset->sourcePath));
73+
}
5274
$asset->addFileDependency($jsFile);
5375

5476
if (($content = file_get_contents($jsFile)) === false) {

src/AssetMapper/TypeScriptPublicPathAssetPathResolver.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public function resolvePublicPath(string $logicalPath): string
2323

2424
public function getPublicFilesystemPath(): string
2525
{
26+
if (!method_exists($this->decorator, 'getPublicFilesystemPath')) {
27+
throw new \LogicException('The decorated resolver does not implement the "getPublicFilesystemPath" method.');
28+
}
2629
$path = $this->decorator->getPublicFilesystemPath();
2730

2831
if (str_ends_with($path, '.ts')) {

src/DependencyInjection/SensiolabsTypeScriptExtension.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ public function load(array $configs, ContainerBuilder $container): void
3939
;
4040
}
4141

42-
public function getConfiguration(array $config, ContainerBuilder $container): ?ConfigurationInterface
42+
/**
43+
* @param array<array<mixed>> $configs
44+
*/
45+
public function getConfiguration(array $configs, ContainerBuilder $container): ConfigurationInterface
4346
{
4447
return $this;
4548
}

src/SensiolabsTypeScriptBundle.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
class SensiolabsTypeScriptBundle extends Bundle
1010
{
11-
public function getContainerExtension(): ?ExtensionInterface
11+
public function getContainerExtension(): ExtensionInterface
1212
{
13-
return $this->extension ?? $this->extension = new SensiolabsTypeScriptExtension();
13+
return $this->extension ?: new SensiolabsTypeScriptExtension();
1414
}
1515
}

src/Tools/TypeScriptBinaryFactory.php

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Sensiolabs\TypeScriptBundle\Tools;
44

5-
use Symfony\Component\Console\Output\OutputInterface;
65
use Symfony\Component\Console\Style\SymfonyStyle;
76
use Symfony\Component\HttpClient\HttpClient;
87
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -11,21 +10,22 @@ class TypeScriptBinaryFactory
1110
{
1211
private const VERSION = 'v1.3.92';
1312
private const SWC_RELEASE_URL_PATTERN = 'https://github.com/swc-project/swc/releases/download/%s/%s';
13+
private HttpClientInterface $httpClient;
14+
private SymfonyStyle $output;
1415

1516
public function __construct(
1617
private readonly string $binaryDownloadDir,
17-
private ?HttpClientInterface $httpClient = null,
18-
private ?OutputInterface $output = null,
18+
?HttpClientInterface $httpClient = null,
1919
) {
2020
$this->httpClient = $httpClient ?? HttpClient::create();
2121
}
2222

23-
public function getBinaryFromPath($pathToExecutable): TypeScriptBinary
23+
public function getBinaryFromPath(string $pathToExecutable): TypeScriptBinary
2424
{
2525
return new TypeScriptBinary($pathToExecutable);
2626
}
2727

28-
public function getBinaryFromServerSpecs($os, $machine, $kernel): TypeScriptBinary
28+
public function getBinaryFromServerSpecs(string $os, string $machine, string $kernel): TypeScriptBinary
2929
{
3030
$binaryName = self::getBinaryNameFromServerSpecs($os, $machine, $kernel);
3131
if (!file_exists($this->binaryDownloadDir.'/'.$binaryName)) {
@@ -35,7 +35,7 @@ public function getBinaryFromServerSpecs($os, $machine, $kernel): TypeScriptBina
3535
return $this->getBinaryFromPath($this->binaryDownloadDir.'/'.$binaryName);
3636
}
3737

38-
public function setOutput(?SymfonyStyle $output): self
38+
public function setOutput(SymfonyStyle $output): self
3939
{
4040
$this->output = $output;
4141

@@ -50,10 +50,10 @@ public function setHttpClient(HttpClientInterface $client): self
5050
}
5151

5252
public static function getBinaryNameFromServerSpecs(
53-
$os,
54-
$machine,
55-
$kernel,
56-
) {
53+
string $os,
54+
string $machine,
55+
string $kernel,
56+
): string {
5757
list($os, $machine, $kernel) = [strtolower($os), strtolower($machine), strtolower($kernel)];
5858
if (str_contains($os, 'darwin')) {
5959
if ('arm64' === $machine) {
@@ -96,7 +96,7 @@ public static function getBinaryNameFromServerSpecs(
9696
throw new \Exception(sprintf('Unknown platform or architecture (OS: %s, Machine: %s).', $os, $machine));
9797
}
9898

99-
private function downloadAndExtract($binaryName): void
99+
private function downloadAndExtract(string $binaryName): void
100100
{
101101
if (!is_dir($this->binaryDownloadDir)) {
102102
mkdir($this->binaryDownloadDir, 0777, true);
@@ -107,10 +107,10 @@ private function downloadAndExtract($binaryName): void
107107
}
108108
$url = sprintf(self::SWC_RELEASE_URL_PATTERN, self::VERSION, $binaryName);
109109

110-
if ($this->output?->isVerbose()) {
111-
$this->output?->note(sprintf('Downloading SWC binary from "%s" to "%s"...', $url, $targetPath));
110+
if ($this->output->isVerbose()) {
111+
$this->output->note(sprintf('Downloading SWC binary from "%s" to "%s"...', $url, $targetPath));
112112
} else {
113-
$this->output?->note('Downloading SWC binary ...');
113+
$this->output->note('Downloading SWC binary ...');
114114
}
115115

116116
$response = $this->httpClient->request('GET', $url, [
@@ -120,20 +120,23 @@ private function downloadAndExtract($binaryName): void
120120
}
121121

122122
if (!$progressBar) {
123-
$progressBar = $this->output?->createProgressBar($dlSize);
123+
$progressBar = $this->output->createProgressBar($dlSize);
124124
}
125125

126-
$progressBar?->setProgress($dlNow);
126+
$progressBar->setProgress($dlNow);
127127
},
128128
]);
129129
$fileHandler = fopen($targetPath, 'w');
130+
if (false === $fileHandler) {
131+
throw new \Exception(sprintf('Could not open file "%s" for writing.', $targetPath));
132+
}
130133
foreach ($this->httpClient->stream($response) as $chunk) {
131134
fwrite($fileHandler, $chunk->getContent());
132135
}
133136

134137
fclose($fileHandler);
135138
$progressBar?->finish();
136-
$this->output?->writeln('');
139+
$this->output->writeln('');
137140

138141
chmod($this->binaryDownloadDir.'/'.$binaryName, 7770);
139142
}

src/Tools/WatcherBinaryFactory.php

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

55
class WatcherBinaryFactory
66
{
7-
public function getBinaryFromServerSpecs($os): WatcherBinary
7+
public function getBinaryFromServerSpecs(string $os): WatcherBinary
88
{
99
$binaryName = self::getBinaryNameFromServerSpecs($os);
1010
$binaryPath = __DIR__.'/watcher/'.$binaryName;
@@ -15,7 +15,7 @@ public function getBinaryFromServerSpecs($os): WatcherBinary
1515
return new WatcherBinary($binaryPath);
1616
}
1717

18-
public static function getBinaryNameFromServerSpecs($os)
18+
public static function getBinaryNameFromServerSpecs(string $os): string
1919
{
2020
$os = strtolower($os);
2121
if (str_contains($os, 'darwin')) {

src/TypeScriptBuilder.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,13 @@
1212

1313
class TypeScriptBuilder
1414
{
15-
private ?SymfonyStyle $output = null;
15+
private SymfonyStyle $output;
1616
private ?TypeScriptBinary $buildBinary = null;
1717
private ?WatcherBinary $watcherBinary = null;
1818

19+
/**
20+
* @param list<string> $typeScriptFilesPaths
21+
*/
1922
public function __construct(
2023
private readonly array $typeScriptFilesPaths,
2124
private readonly string $compiledFilesPaths,
@@ -47,8 +50,8 @@ private function createBuildProcess(string $path, bool $watch = false): Process
4750
$buildProcess = $this->getBuildBinary()->createProcess(array_merge(['compile', $relativePath], $args));
4851
$buildProcess->setWorkingDirectory($this->projectRootDir);
4952

50-
$this->output?->note(sprintf('Executing SWC compile on %s.', $relativePath));
51-
if ($this->output?->isVerbose()) {
53+
$this->output->note(sprintf('Executing SWC compile on %s.', $relativePath));
54+
if ($this->output->isVerbose()) {
5255
$this->output->writeln([
5356
' Command:',
5457
' '.$buildProcess->getCommandLine(),

0 commit comments

Comments
 (0)