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;
25
26use function Safe\getcwd;
27
28/**
29 * Provides canonical repository-root paths that are not part of the managed workspace.
30 */
31 class WorkingProjectPathResolver
32{
33    /**
34     * @var list<string> repository-local directories ignored by tooling
35     */
36    public const array TOOLING_EXCLUDED_DIRECTORIES = [
37        '.dev-tools',
38        'backup',
39        'cache',
40        'public',
41        'resources',
42        'tmp',
43        'vendor',
44        '*/vendor',
45        '*/vendor/*',
46        '**/vendor',
47        '**/vendor/*',
48    ];
49
50    /**
51     * Returns the current working project directory or a path under it.
52     *
53     * @param string $path the optional relative segment to append under the project directory
54     */
55    public static function getProjectPath(string $path = ''): string
56    {
57        if ('' !== $path && Path::isAbsolute($path)) {
58            return $path;
59        }
60
61        return Path::join(getcwd(), $path);
62    }
63
64    /**
65     * Returns the project directories that static-analysis and coding-style tooling SHOULD skip.
66     *
67     * @param string $baseDir the optional repository base directory used to materialize absolute paths
68     * @param EnvironmentInterface|null $environment explicit environment reader used to resolve FAST_FORWARD_WORKSPACE_DIR
69     *
70     * @return list<string>
71     */
72    public static function getToolingExcludedDirectories(
73        string $baseDir = '',
74        ?EnvironmentInterface $environment = null,
75    ): array {
76        $directories = [];
77
78        foreach (self::getToolingExcludedDirectoryNames($baseDir, $environment) as $excludedDirectory) {
79            $directories[] = Path::join($baseDir, $excludedDirectory);
80        }
81
82        return $directories;
83    }
84
85    /**
86     * Returns PHP source files that tooling SHOULD inspect without traversing generated directories.
87     *
88     * @param string $baseDir the optional repository base directory used to materialize absolute paths
89     * @param EnvironmentInterface|null $environment explicit environment reader used to resolve FAST_FORWARD_WORKSPACE_DIR
90     *
91     * @return list<string>
92     */
93    public static function getToolingSourcePaths(
94        string $baseDir = '',
95        ?EnvironmentInterface $environment = null,
96    ): array {
97        $workingDirectory = '' === $baseDir ? getcwd() : $baseDir;
98        $excludedDirectories = self::getToolingExcludedDirectoryNames($workingDirectory, $environment);
99        $finder = Finder::create()
100            ->files()
101            ->name('*.php')
102            ->in($workingDirectory)
103            ->exclude($excludedDirectories)
104            ->sortByName();
105        $paths = [];
106
107        foreach ($finder as $file) {
108            $realPath = $file->getRealPath();
109
110            if (false === $realPath) {
111                continue;
112            }
113
114            $relativePath = Path::makeRelative($realPath, $workingDirectory);
115            $paths[] = Path::join($baseDir, $relativePath);
116        }
117
118        return $paths;
119    }
120
121    /**
122     * Returns repository-relative directories ignored by tooling.
123     *
124     * @param string $baseDir the optional repository base directory used to relativize a custom workspace
125     * @param EnvironmentInterface|null $environment explicit environment reader used to resolve FAST_FORWARD_WORKSPACE_DIR
126     *
127     * @return list<string>
128     */
129    private static function getToolingExcludedDirectoryNames(
130        string $baseDir = '',
131        ?EnvironmentInterface $environment = null,
132    ): array {
133        $directories = self::TOOLING_EXCLUDED_DIRECTORIES;
134        $workspaceRoot = ManagedWorkspace::getProjectRelativeWorkspaceRoot(
135            baseDir: $baseDir,
136            environment: $environment
137        );
138
139        if (null !== $workspaceRoot && ! \in_array($workspaceRoot, $directories, true)) {
140            $directories[] = $workspaceRoot;
141        }
142
143        return $directories;
144    }
145}