Skip to content

Commit

Permalink
[DX] Use own path normalizer (#2881)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomasVotruba committed Sep 1, 2022
1 parent a80c361 commit 36ac530
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/rector.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
-
# commit only to core contributors who have repository access
if: github.event.pull_request.head.repo.full_name == github.repository
uses: EndBug/add-and-commit@v9.1.0
uses: EndBug/add-and-commit@v7.5.0
with:
# The arguments for the `git add` command (see the paragraph below for more info)
add: .
Expand Down
8 changes: 0 additions & 8 deletions config/config.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@
use Symplify\PackageBuilder\Reflection\PrivatesAccessor;
use Symplify\PackageBuilder\Reflection\PrivatesCaller;
use Symplify\PackageBuilder\Yaml\ParametersMerger;
use Symplify\SmartFileSystem\FileSystemFilter;
use Symplify\SmartFileSystem\FileSystemGuard;
use Symplify\SmartFileSystem\Finder\FinderSanitizer;
use Symplify\SmartFileSystem\Normalizer\PathNormalizer;

return static function (RectorConfig $rectorConfig): void {
// make use of https://github.com/symplify/easy-parallel
Expand Down Expand Up @@ -178,11 +174,8 @@
->factory([service(PHPStanServicesFactory::class), 'createEmulativeLexer']);

// symplify/package-builder
$services->set(FileSystemGuard::class);
$services->set(PrivatesAccessor::class);
$services->set(PrivatesCaller::class);
$services->set(FinderSanitizer::class);
$services->set(FileSystemFilter::class);

$services->set(ParameterProvider::class)
->arg('$container', service('service_container'));
Expand Down Expand Up @@ -247,5 +240,4 @@

// skipper
$services->set(ClassLikeExistenceChecker::class);
$services->set(PathNormalizer::class);
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
namespace Rector\Skipper\SkipCriteriaResolver;

use Rector\Core\Configuration\Option;
use Rector\Core\FileSystem\FilePathHelper;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\SmartFileSystem\Normalizer\PathNormalizer;

/**
* @see \Rector\Tests\Skipper\SkipCriteriaResolver\SkippedPathsResolver\SkippedPathsResolverTest
Expand All @@ -20,7 +20,7 @@ final class SkippedPathsResolver

public function __construct(
private readonly ParameterProvider $parameterProvider,
private readonly PathNormalizer $pathNormalizer
private readonly FilePathHelper $filePathHelper
) {
}

Expand All @@ -41,13 +41,12 @@ public function resolve(): array
}

if (file_exists($value)) {
$this->skippedPaths[] = $this->pathNormalizer->normalizePath($value);
$this->skippedPaths[] = $this->filePathHelper->normalizePathAndSchema($value);
continue;
}

if (\str_contains((string) $value, '*')) {
$this->skippedPaths[] = $this->pathNormalizer->normalizePath($value);
continue;
$this->skippedPaths[] = $this->filePathHelper->normalizePathAndSchema($value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@

use PhpParser\Node\Stmt\ClassMethod;
use PHPStan\Reflection\ClassReflection;
use Rector\Core\FileSystem\FilePathHelper;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\FamilyTree\Reflection\FamilyRelationsAnalyzer;
use Rector\NodeNameResolver\NodeNameResolver;
use Symplify\SmartFileSystem\Normalizer\PathNormalizer;

final class ClassMethodParamVendorLockResolver
{
public function __construct(
private readonly NodeNameResolver $nodeNameResolver,
private readonly PathNormalizer $pathNormalizer,
private readonly FamilyRelationsAnalyzer $familyRelationsAnalyzer,
private readonly ReflectionResolver $reflectionResolver
private readonly ReflectionResolver $reflectionResolver,
private readonly FilePathHelper $filePathHelper
) {
}

Expand Down Expand Up @@ -124,7 +124,7 @@ private function hasClassMethodLockMatchingFileName(
return true;
}

$normalizedFileName = $this->pathNormalizer->normalizePath($fileName);
$normalizedFileName = $this->filePathHelper->normalizePathAndSchema($fileName);
if (str_contains($normalizedFileName, $filePathPartName)) {
return true;
}
Expand Down
10 changes: 5 additions & 5 deletions packages/VendorLocker/ParentClassMethodTypeOverrideGuard.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,25 @@
use PHPStan\Reflection\ParametersAcceptorSelector;
use PHPStan\Type\MixedType;
use PHPStan\Type\Type;
use Rector\Core\FileSystem\FilePathHelper;
use Rector\Core\PhpParser\AstResolver;
use Rector\Core\Reflection\ReflectionResolver;
use Rector\Core\ValueObject\MethodName;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\TypeComparator\TypeComparator;
use Rector\StaticTypeMapper\StaticTypeMapper;
use Rector\TypeDeclaration\TypeInferer\ParamTypeInferer;
use Symplify\SmartFileSystem\Normalizer\PathNormalizer;

final class ParentClassMethodTypeOverrideGuard
{
public function __construct(
private readonly NodeNameResolver $nodeNameResolver,
private readonly PathNormalizer $pathNormalizer,
private readonly AstResolver $astResolver,
private readonly ParamTypeInferer $paramTypeInferer,
private readonly ReflectionResolver $reflectionResolver,
private readonly TypeComparator $typeComparator,
private readonly StaticTypeMapper $staticTypeMapper
private readonly StaticTypeMapper $staticTypeMapper,
private readonly FilePathHelper $filePathHelper
) {
}

Expand Down Expand Up @@ -78,11 +78,11 @@ public function isReturnTypeChangeAllowed(ClassMethod $classMethod): bool
$currentFileName = $currentClassReflection->getFileName();

// child (current)
$normalizedCurrentFileName = $this->pathNormalizer->normalizePath($currentFileName);
$normalizedCurrentFileName = $this->filePathHelper->normalizePathAndSchema($currentFileName);
$isCurrentInVendor = str_contains($normalizedCurrentFileName, '/vendor/');

// parent
$normalizedFileName = $this->pathNormalizer->normalizePath($fileName);
$normalizedFileName = $this->filePathHelper->normalizePathAndSchema($fileName);
$isParentInVendor = str_contains($normalizedFileName, '/vendor/');

return ($isCurrentInVendor && $isParentInVendor) || (! $isCurrentInVendor && ! $isParentInVendor);
Expand Down
4 changes: 4 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -784,3 +784,7 @@ parameters:
message: '#Instead of "instanceof/is_a\(\)" use ReflectionProvider service or "\(new ObjectType\(<desired_type>\)\)\->isSuperTypeOf\(<element_type>\)" for static reflection to work#'
path: packages/Skipper/Skipper/SkipSkipper.php

# split of string schema
-
message: '#Array destruct is not allowed\. Use value object to pass data instead#'
path: src/FileSystem/FilePathHelper.php
6 changes: 3 additions & 3 deletions rules/CodingStyle/Reflection/VendorLocationDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
namespace Rector\CodingStyle\Reflection;

use PHPStan\Reflection\MethodReflection;
use Symplify\SmartFileSystem\Normalizer\PathNormalizer;
use Rector\Core\FileSystem\FilePathHelper;

final class VendorLocationDetector
{
public function __construct(
private readonly PathNormalizer $pathNormalizer,
private readonly FilePathHelper $filePathHelper
) {
}

Expand All @@ -24,7 +24,7 @@ public function detectMethodReflection(MethodReflection $methodReflection): bool
return false;
}

$normalizedFileName = $this->pathNormalizer->normalizePath($fileName);
$normalizedFileName = $this->filePathHelper->normalizePathAndSchema($fileName);
return str_contains($normalizedFileName, '/vendor/');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function run()
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
use Symplify\SmartFileSystem\SmartFileSystem;
use App\Custom\SmartFileSystem;
class SomeClass
{
Expand All @@ -77,7 +77,7 @@ public function run()
new StaticCallToMethodCall(
'Nette\Utils\FileSystem',
'write',
'Symplify\SmartFileSystem\SmartFileSystem',
'App\Custom\SmartFileSystem',
'dumpFile'
),
]
Expand Down
83 changes: 83 additions & 0 deletions src/FileSystem/FilePathHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,32 @@

namespace Rector\Core\FileSystem;

use Nette\Utils\Strings;
use Symfony\Component\Filesystem\Filesystem;
use Webmozart\Assert\Assert;

/**
* @see \Rector\Core\Tests\FileSystem\FilePathHelperTest
*/
final class FilePathHelper
{
/**
* @see https://regex101.com/r/d4F5Fm/1
* @var string
*/
private const SCHEME_PATH_REGEX = '#^([a-z]+)\\:\\/\\/(.+)#';

/**
* @see https://regex101.com/r/no28vw/1
* @var string
*/
private const TWO_AND_MORE_SLASHES_REGEX = '#/{2,}#';

/**
* @var string
*/
private const SCHEME_UNDEFINED = 'undefined';

public function __construct(
private readonly Filesystem $filesystem,
) {
Expand Down Expand Up @@ -37,8 +58,70 @@ public function relativeFilePathFromDirectory(string $fileRealPath, string $dire
return rtrim($relativeFilePath, '/');
}

/**
* Used from
* https://github.com/phpstan/phpstan-src/blob/02425e61aa48f0668b4efb3e73d52ad544048f65/src/File/FileHelper.php#L40, with custom modifications
*/
public function normalizePathAndSchema(string $originalPath): string
{
$directorySeparator = DIRECTORY_SEPARATOR;

$matches = Strings::match($originalPath, self::SCHEME_PATH_REGEX);
if ($matches !== null) {
[, $scheme, $path] = $matches;
} else {
$scheme = self::SCHEME_UNDEFINED;
$path = $originalPath;
}

$normalizedPath = str_replace('\\', '/', (string) $path);
$path = Strings::replace($normalizedPath, self::TWO_AND_MORE_SLASHES_REGEX, '/');

$pathRoot = str_starts_with($path, '/') ? $directorySeparator : '';
$pathParts = explode('/', trim($path, '/'));

$normalizedPathParts = $this->normalizePathParts($pathParts, $scheme);

$pathStart = ($scheme !== self::SCHEME_UNDEFINED ? $scheme . '://' : '');
return $pathStart . $pathRoot . implode($directorySeparator, $normalizedPathParts);
}

private function normalizePath(string $filePath): string
{
return \str_replace('\\', '/', $filePath);
}

/**
* @param string[] $pathParts
* @return string[]
*/
private function normalizePathParts(array $pathParts, string $scheme): array
{
$normalizedPathParts = [];

foreach ($pathParts as $pathPart) {
if ($pathPart === '.') {
continue;
}

if ($pathPart !== '..') {
$normalizedPathParts[] = $pathPart;
continue;
}

/** @var string $removedPart */
$removedPart = array_pop($normalizedPathParts);
if ($scheme !== 'phar') {
continue;
}

if (! \str_ends_with($removedPart, '.phar')) {
continue;
}

$scheme = self::SCHEME_UNDEFINED;
}

return $normalizedPathParts;
}
}
36 changes: 36 additions & 0 deletions tests/FileSystem/FilePathHelperTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Rector\Core\Tests\FileSystem;

use Iterator;
use PHPUnit\Framework\TestCase;
use Rector\Core\FileSystem\FilePathHelper;
use Symfony\Component\Filesystem\Filesystem;

final class FilePathHelperTest extends TestCase
{
private FilePathHelper $filePathHelper;

protected function setUp(): void
{
$this->filePathHelper = new FilePathHelper(new Filesystem());
}

/**
* @dataProvider provideData()
*/
public function test(string $inputPath, string $expectedNormalizedPath): void
{
$normalizedPath = $this->filePathHelper->normalizePathAndSchema($inputPath);
$this->assertSame($expectedNormalizedPath, $normalizedPath);
}

public function provideData(): Iterator
{
// based on Linux
yield ['/any/path', '/any/path'];
yield ['\any\path', '/any/path'];
}
}

0 comments on commit 36ac530

Please sign in to comment.