Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.43% covered (success)
96.43%
27 / 28
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
WorkingProjectPathResolver
96.43% covered (success)
96.43%
27 / 28
75.00% covered (warning)
75.00%
3 / 4
12
0.00% covered (danger)
0.00%
0 / 1
 getProjectPath
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getToolingExcludedDirectories
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getToolingSourcePaths
93.75% covered (success)
93.75%
15 / 16
0.00% covered (danger)
0.00%
0 / 1
4.00
 getToolingExcludedDirectoryNames
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\Path;
21
22use Symfony\Component\Finder\Finder;
23use Symfony\Component\Filesystem\Path;
24
25use function Safe\getcwd;
26
27/**
28 * Provides canonical repository-root paths that are not part of the managed workspace.
29 */
30 class WorkingProjectPathResolver
31{
32    /**
33     * @var list<string> repository-local directories ignored by tooling
34     */
35    public const array TOOLING_EXCLUDED_DIRECTORIES = [
36        '.dev-tools',
37        'backup',
38        'cache',
39        'public',
40        'resources',
41        'tmp',
42        'vendor',
43        '*/vendor',
44        '*/vendor/*',
45        '**/vendor',
46        '**/vendor/*',
47    ];
48
49    /**
50     * Returns the current working project directory or a path under it.
51     *
52     * @param string $path the optional relative segment to append under the project directory
53     */
54    public static function getProjectPath(string $path = ''): string
55    {
56        if ('' !== $path && Path::isAbsolute($path)) {
57            return $path;
58        }
59
60        return Path::join(getcwd(), $path);
61    }
62
63    /**
64     * Returns the project directories that static-analysis and coding-style tooling SHOULD skip.
65     *
66     * @param string $baseDir the optional repository base directory used to materialize absolute paths
67     *
68     * @return list<string>
69     */
70    public static function getToolingExcludedDirectories(string $baseDir = ''): array
71    {
72        $directories = [];
73
74        foreach (self::getToolingExcludedDirectoryNames($baseDir) as $excludedDirectory) {
75            $directories[] = Path::join($baseDir, $excludedDirectory);
76        }
77
78        return $directories;
79    }
80
81    /**
82     * Returns PHP source files that tooling SHOULD inspect without traversing generated directories.
83     *
84     * @param string $baseDir the optional repository base directory used to materialize absolute paths
85     *
86     * @return list<string>
87     */
88    public static function getToolingSourcePaths(string $baseDir = ''): array
89    {
90        $workingDirectory = '' === $baseDir ? getcwd() : $baseDir;
91        $excludedDirectories = self::getToolingExcludedDirectoryNames($workingDirectory);
92        $finder = Finder::create()
93            ->files()
94            ->name('*.php')
95            ->in($workingDirectory)
96            ->exclude($excludedDirectories)
97            ->sortByName();
98        $paths = [];
99
100        foreach ($finder as $file) {
101            $realPath = $file->getRealPath();
102
103            if (false === $realPath) {
104                continue;
105            }
106
107            $relativePath = Path::makeRelative($realPath, $workingDirectory);
108            $paths[] = Path::join($baseDir, $relativePath);
109        }
110
111        return $paths;
112    }
113
114    /**
115     * Returns repository-relative directories ignored by tooling.
116     *
117     * @param string $baseDir the optional repository base directory used to relativize a custom workspace
118     *
119     * @return list<string>
120     */
121    private static function getToolingExcludedDirectoryNames(string $baseDir = ''): array
122    {
123        $directories = self::TOOLING_EXCLUDED_DIRECTORIES;
124        $workspaceRoot = ManagedWorkspace::getProjectRelativeWorkspaceRoot($baseDir);
125
126        if (null !== $workspaceRoot && ! \in_array($workspaceRoot, $directories, true)) {
127            $directories[] = $workspaceRoot;
128        }
129
130        return $directories;
131    }
132}