-
-
Notifications
You must be signed in to change notification settings - Fork 439
Expand file tree
/
Copy pathFilePathHelper.php
More file actions
114 lines (90 loc) · 3.29 KB
/
FilePathHelper.php
File metadata and controls
114 lines (90 loc) · 3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<?php
declare(strict_types=1);
namespace Rector\FileSystem;
use Nette\Utils\Strings;
use Rector\Skipper\FileSystem\PathNormalizer;
use Symfony\Component\Filesystem\Filesystem;
use Webmozart\Assert\Assert;
/**
* @see \Rector\Tests\FileSystem\FilePathHelperTest
*/
final readonly class FilePathHelper
{
/**
* @see https://regex101.com/r/d4F5Fm/1
*/
private const string SCHEME_PATH_REGEX = '#^([a-z]+)\\:\\/\\/(.+)#';
/**
* @see https://regex101.com/r/no28vw/1
*/
private const string TWO_AND_MORE_SLASHES_REGEX = '#/{2,}#';
private const string SCHEME_UNDEFINED = 'undefined';
public function __construct(
private Filesystem $filesystem,
) {
}
public function relativePath(string $fileRealPath): string
{
if (! $this->filesystem->isAbsolutePath($fileRealPath)) {
return $fileRealPath;
}
return $this->relativeFilePathFromDirectory($fileRealPath, getcwd());
}
/**
* 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 = PathNormalizer::normalize((string) $path);
$path = Strings::replace($normalizedPath, self::TWO_AND_MORE_SLASHES_REGEX, '/');
$pathRoot = str_starts_with($path, '/') ? $directorySeparator : '';
$pathParts = explode('/', trim($path, '/'));
/** @var string $scheme */
$normalizedPathParts = $this->normalizePathParts($pathParts, $scheme);
$pathStart = ($scheme !== self::SCHEME_UNDEFINED ? $scheme . '://' : '');
return PathNormalizer::normalize($pathStart . $pathRoot . implode($directorySeparator, $normalizedPathParts));
}
private function relativeFilePathFromDirectory(string $fileRealPath, string $directory): string
{
Assert::directory($directory);
$normalizedFileRealPath = PathNormalizer::normalize($fileRealPath);
$relativeFilePath = $this->filesystem->makePathRelative($normalizedFileRealPath, $directory);
return rtrim($relativeFilePath, '/');
}
/**
* @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;
}
}