Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.77% covered (success)
96.77%
30 / 31
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
WorkingProjectPathResolver
96.77% covered (success)
96.77%
30 / 31
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%
8 / 8
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 FastForward\DevTools\Environment\EnvironmentInterface;
23use Symfony\Component\Finder\Finder;
24use Symfony\Component\Filesystem\Path;
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     * @param EnvironmentInterface|null $environment explicit environment reader used to resolve FAST_FORWARD_WORKSPACE_DIR
68     *
69     * @return list<string>
70     */
71    public static function getToolingExcludedDirectories(
72        string $baseDir = '',
73        ?EnvironmentInterface $environment = null,
74    ): array {
75        $directories = [];
76
77        foreach (self::getToolingExcludedDirectoryNames($baseDir, $environment) as $excludedDirectory) {
78            $directories[] = Path::join($baseDir, $excludedDirectory);
79        }
80
81        return $directories;
82    }
83
84    /**
85     * Returns PHP source files that tooling SHOULD inspect without traversing generated directories.
86     *
87     * @param string $baseDir the optional repository base directory used to materialize absolute paths
88     * @param EnvironmentInterface|null $environment explicit environment reader used to resolve FAST_FORWARD_WORKSPACE_DIR
89     *
90     * @return list<string>
91     */
92    public static function getToolingSourcePaths(
93        string $baseDir = '',
94        ?EnvironmentInterface $environment = null,
95    ): array {
96        $workingDirectory = '' === $baseDir ? getcwd() : $baseDir;
97        $excludedDirectories = self::getToolingExcludedDirectoryNames($workingDirectory, $environment);
98        $finder = Finder::create()
99            ->files()
100            ->name('*.php')
101            ->in($workingDirectory)
102            ->exclude($excludedDirectories)
103            ->sortByName();
104        $paths = [];
105
106        foreach ($finder as $file) {
107            $realPath = $file->getRealPath();
108
109            if (false === $realPath) {
110                continue;
111            }
112
113            $relativePath = Path::makeRelative($realPath, $workingDirectory);
114            $paths[] = Path::join($baseDir, $relativePath);
115        }
116
117        return $paths;
118    }
119
120    /**
121     * Returns repository-relative directories ignored by tooling.
122     *
123     * @param string $baseDir the optional repository base directory used to relativize a custom workspace
124     * @param EnvironmentInterface|null $environment explicit environment reader used to resolve FAST_FORWARD_WORKSPACE_DIR
125     *
126     * @return list<string>
127     */
128    private static function getToolingExcludedDirectoryNames(
129        string $baseDir = '',
130        ?EnvironmentInterface $environment = null,
131    ): array {
132        $directories = self::TOOLING_EXCLUDED_DIRECTORIES;
133        $workspaceRoot = ManagedWorkspace::getProjectRelativeWorkspaceRoot(
134            baseDir: $baseDir,
135            environment: $environment
136        );
137
138        if (null !== $workspaceRoot && ! \in_array($workspaceRoot, $directories, true)) {
139            $directories[] = $workspaceRoot;
140        }
141
142        return $directories;
143    }
144}