Skip to content

Commit 18e1d9d

Browse files
committed
Simplify DevTools path resolution helpers
1 parent 4ade07c commit 18e1d9d

1 file changed

Lines changed: 122 additions & 62 deletions

File tree

src/Path/DevToolsPathResolver.php

Lines changed: 122 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,7 @@ final class DevToolsPathResolver
4949
*/
5050
public static function getPackagePath(string $path = ''): string
5151
{
52-
$packageDirectory = \dirname(__DIR__, 2);
53-
54-
if ('' !== $path && Path::isAbsolute($path)) {
55-
throw new InvalidArgumentException('The DevTools package path MUST be relative to the package root.');
56-
}
57-
58-
return Path::join($packageDirectory, $path);
52+
return self::resolvePackageRelativePath($path);
5953
}
6054

6155
/**
@@ -104,19 +98,10 @@ public static function getPackagePathRelativeToProject(
10498
string $projectPath = '',
10599
string $packagePath = '',
106100
): string {
107-
if (Path::isAbsolute($path)) {
108-
throw new InvalidArgumentException('The DevTools package path MUST be relative to the package root.');
109-
}
110-
111-
$projectPath = Path::canonicalize(WorkingProjectPathResolver::getProjectPath($projectPath));
112-
$packagePath = Path::canonicalize('' === $packagePath ? self::getPackagePath() : $packagePath);
113-
$packageFilePath = Path::canonicalize(Path::join($packagePath, $path));
114-
115-
try {
116-
return Path::makeRelative($packageFilePath, $projectPath);
117-
} catch (InvalidArgumentException) {
118-
return $packageFilePath;
119-
}
101+
return self::relativizePathFromProject(
102+
self::resolvePackageRelativePath($path, $packagePath),
103+
self::resolveProjectPath($projectPath),
104+
);
120105
}
121106

122107
/**
@@ -130,13 +115,7 @@ public static function getPackagePathRelativeToProject(
130115
*/
131116
public static function getRuntimeAutoloadPath(string $packagePath = ''): string
132117
{
133-
$packagePath = Path::canonicalize('' === $packagePath ? self::getPackagePath() : $packagePath);
134-
135-
if (self::isInstalledAsDependency($packagePath)) {
136-
return Path::canonicalize(Path::join($packagePath, '..', '..', 'autoload.php'));
137-
}
138-
139-
return Path::join($packagePath, 'vendor', 'autoload.php');
118+
return Path::join(self::getRuntimeVendorRoot($packagePath), 'autoload.php');
140119
}
141120

142121
/**
@@ -150,13 +129,7 @@ public static function getRuntimeAutoloadPath(string $packagePath = ''): string
150129
*/
151130
public static function getRuntimeToolBinaryPath(string $binary, string $packagePath = ''): string
152131
{
153-
$packagePath = Path::canonicalize('' === $packagePath ? self::getPackagePath() : $packagePath);
154-
155-
if (self::isInstalledAsDependency($packagePath)) {
156-
return Path::canonicalize(Path::join($packagePath, '..', '..', 'bin', $binary));
157-
}
158-
159-
return Path::join($packagePath, 'vendor', 'bin', $binary);
132+
return self::getRuntimeVendorPath(Path::join('bin', $binary), $packagePath);
160133
}
161134

162135
/**
@@ -170,14 +143,7 @@ public static function getRuntimeToolBinaryPath(string $binary, string $packageP
170143
*/
171144
public static function getRuntimeVendorPath(string $path, string $packagePath = ''): string
172145
{
173-
$packagePath = Path::canonicalize('' === $packagePath ? self::getPackagePath() : $packagePath);
174-
$vendorPath = self::normalizeVendorRelativePath($path);
175-
176-
if (self::isInstalledAsDependency($packagePath)) {
177-
return Path::canonicalize(Path::join($packagePath, '..', '..', $vendorPath));
178-
}
179-
180-
return Path::join($packagePath, 'vendor', $vendorPath);
146+
return Path::join(self::getRuntimeVendorRoot($packagePath), self::normalizeVendorRelativePath($path));
181147
}
182148

183149
/**
@@ -196,14 +162,10 @@ public static function getPreferredToolBinaryPath(
196162
string $projectPath = '',
197163
string $packagePath = '',
198164
): string {
199-
$projectPath = '' === $projectPath ? WorkingProjectPathResolver::getProjectPath() : $projectPath;
200-
$projectBinaryPath = Path::join($projectPath, 'vendor', 'bin', $binary);
201-
202-
if (file_exists($projectBinaryPath)) {
203-
return $projectBinaryPath;
204-
}
205-
206-
return self::getRuntimeToolBinaryPath($binary, $packagePath);
165+
return self::preferExistingPath(
166+
self::getProjectVendorPath(Path::join('bin', $binary), $projectPath),
167+
self::getRuntimeToolBinaryPath($binary, $packagePath),
168+
);
207169
}
208170

209171
/**
@@ -222,15 +184,10 @@ public static function getPreferredVendorPath(
222184
string $projectPath = '',
223185
string $packagePath = '',
224186
): string {
225-
$projectPath = '' === $projectPath ? WorkingProjectPathResolver::getProjectPath() : $projectPath;
226-
$vendorPath = self::normalizeVendorRelativePath($path);
227-
$projectVendorPath = Path::join($projectPath, 'vendor', $vendorPath);
228-
229-
if (file_exists($projectVendorPath)) {
230-
return $projectVendorPath;
231-
}
232-
233-
return self::getRuntimeVendorPath($vendorPath, $packagePath);
187+
return self::preferExistingPath(
188+
self::getProjectVendorPath($path, $projectPath),
189+
self::getRuntimeVendorPath($path, $packagePath),
190+
);
234191
}
235192

236193
/**
@@ -240,9 +197,7 @@ public static function getPreferredVendorPath(
240197
*/
241198
public static function isInstalledAsDependency(string $packagePath = ''): bool
242199
{
243-
$packagePath = Path::canonicalize('' === $packagePath ? self::getPackagePath() : $packagePath);
244-
245-
return str_contains($packagePath, self::VENDOR_PACKAGE_PATH);
200+
return str_contains(self::resolvePackageRoot($packagePath), self::VENDOR_PACKAGE_PATH);
246201
}
247202

248203
/**
@@ -270,4 +225,109 @@ private static function normalizeVendorRelativePath(string $path): string
270225

271226
return $path;
272227
}
228+
229+
/**
230+
* Ensures packaged paths stay relative to the DevTools package root.
231+
*
232+
* @param string $path the package-relative path to validate
233+
*/
234+
private static function assertRelativePackagePath(string $path): void
235+
{
236+
if ('' !== $path && Path::isAbsolute($path)) {
237+
throw new InvalidArgumentException('The DevTools package path MUST be relative to the package root.');
238+
}
239+
}
240+
241+
/**
242+
* Returns a canonical path under the DevTools package root.
243+
*
244+
* @param string $path the package-relative path to resolve
245+
* @param string $packagePath an optional package root path; defaults to the current package root
246+
*/
247+
private static function resolvePackageRelativePath(string $path = '', string $packagePath = ''): string
248+
{
249+
self::assertRelativePackagePath($path);
250+
251+
return Path::canonicalize(Path::join(self::resolvePackageRoot($packagePath), $path));
252+
}
253+
254+
/**
255+
* Returns the canonical DevTools package root.
256+
*
257+
* @param string $packagePath an optional package root path; defaults to the current package root
258+
*/
259+
private static function resolvePackageRoot(string $packagePath = ''): string
260+
{
261+
return Path::canonicalize('' === $packagePath ? \dirname(__DIR__, 2) : $packagePath);
262+
}
263+
264+
/**
265+
* Returns the canonical working project root.
266+
*
267+
* @param string $projectPath an optional project root path; defaults to the working project root
268+
*/
269+
private static function resolveProjectPath(string $projectPath = ''): string
270+
{
271+
return Path::canonicalize(WorkingProjectPathResolver::getProjectPath($projectPath));
272+
}
273+
274+
/**
275+
* Returns the active Composer vendor root for the current DevTools installation mode.
276+
*
277+
* @param string $packagePath an optional package root path; defaults to the current package root
278+
*/
279+
private static function getRuntimeVendorRoot(string $packagePath = ''): string
280+
{
281+
$packagePath = self::resolvePackageRoot($packagePath);
282+
283+
if (self::isInstalledAsDependency($packagePath)) {
284+
return Path::canonicalize(Path::join($packagePath, '..', '..'));
285+
}
286+
287+
return Path::join($packagePath, 'vendor');
288+
}
289+
290+
/**
291+
* Returns a vendor path under the active project root.
292+
*
293+
* @param string $path the vendor-relative path to resolve
294+
* @param string $projectPath an optional project root path; defaults to the working project root
295+
*/
296+
private static function getProjectVendorPath(string $path, string $projectPath = ''): string
297+
{
298+
return Path::join(self::resolveProjectPath($projectPath), 'vendor', self::normalizeVendorRelativePath($path));
299+
}
300+
301+
/**
302+
* Returns the preferred path when a project-local candidate exists.
303+
*
304+
* @param string $preferredPath the project-local candidate path
305+
* @param string $fallbackPath the runtime fallback path
306+
*/
307+
private static function preferExistingPath(string $preferredPath, string $fallbackPath): string
308+
{
309+
if (file_exists($preferredPath)) {
310+
return $preferredPath;
311+
}
312+
313+
return $fallbackPath;
314+
}
315+
316+
/**
317+
* Returns a path relative to the project root when possible.
318+
*
319+
* When paths do not share the same filesystem root, the original absolute
320+
* path MUST be returned unchanged so callers still receive a usable path.
321+
*
322+
* @param string $path the absolute path to relativize
323+
* @param string $projectPath the absolute project root used as base path
324+
*/
325+
private static function relativizePathFromProject(string $path, string $projectPath): string
326+
{
327+
try {
328+
return Path::makeRelative($path, $projectPath);
329+
} catch (InvalidArgumentException) {
330+
return $path;
331+
}
332+
}
273333
}

0 commit comments

Comments
 (0)