Skip to content

Commit

Permalink
Merge pull request #1208 from phpDocumentor/cleanup-run-command
Browse files Browse the repository at this point in the history
Improved exclude file options
  • Loading branch information
jaapio authored Feb 28, 2025
2 parents 8e7c01f + bd0e218 commit 175f443
Show file tree
Hide file tree
Showing 22 changed files with 826 additions and 154 deletions.
3 changes: 2 additions & 1 deletion packages/filesystem/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
},
"minimum-stability": "stable",
"require": {
"php": "^8.1"
"php": "^8.1",
"webmozart/assert": "^1.3"
},
"extra": {
"branch-alias": {
Expand Down
72 changes: 72 additions & 0 deletions packages/filesystem/src/Finder/Exclude.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\FileSystem\Finder;

use phpDocumentor\FileSystem\Path;

use function array_map;
use function array_values;
use function str_starts_with;

final class Exclude
{
/** @var list<string> */
private readonly array $paths;

/** @param list<string|Path> $paths */
public function __construct(
array $paths = [],
private readonly bool $hidden = false,
private readonly bool $symlinks = false,
) {
$this->paths = array_values(
array_map(
static function (string|Path $path): string {
if (str_starts_with((string) $path, '/')) {
return (string) $path;
}

return '/' . $path;
},
$paths,
),
);
}

/** @return list<string> */
public function getPaths(): array
{
return $this->paths;
}

public function excludeHidden(): bool
{
return $this->hidden;
}

public function followSymlinks(): bool
{
return $this->symlinks;
}

/** @param list<string|path> $excludePaths */
public function withPaths(array $excludePaths): self
{
return new self(
$excludePaths,
$this->hidden,
$this->symlinks,
);
}
}
83 changes: 83 additions & 0 deletions packages/filesystem/src/Finder/SpecificationFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\FileSystem\Finder;

use Flyfinder\Path as FlyFinderPath;
use Flyfinder\Specification\Glob;
use Flyfinder\Specification\HasExtension;
use Flyfinder\Specification\InPath;
use Flyfinder\Specification\IsHidden;
use Flyfinder\Specification\NotSpecification;
use Flyfinder\Specification\SpecificationInterface;
use phpDocumentor\FileSystem\Path;

/**
* Factory class to build Specification used by FlyFinder when reading files to process.
*/
final class SpecificationFactory implements SpecificationFactoryInterface
{
/**
* Creates a SpecificationInterface object based on the ignore and extension parameters.
*
* @param list<string|Path> $paths
* @param list<string> $extensions
*/
public function create(array $paths, Exclude $ignore, array $extensions): SpecificationInterface
{
/** @var ?Glob $pathSpec */
$pathSpec = null;
foreach ($paths as $path) {
if ($path instanceof Path) {
$condition = new InPath(new FlyFinderPath((string) $path));
} else {
$condition = new Glob($path);
}

if ($pathSpec === null) {
$pathSpec = $condition;
continue;
}

$pathSpec = $pathSpec->orSpecification($condition);
}

/** @var ?Glob $ignoreSpec */
$ignoreSpec = null;
foreach ($ignore->getPaths() as $path) {
if ($ignoreSpec === null) {
$ignoreSpec = new Glob($path);
continue;
}

$ignoreSpec = $ignoreSpec->orSpecification(new Glob($path));
}

if ($ignore->excludeHidden()) {
$ignoreSpec = $ignoreSpec === null
? new IsHidden()
: $ignoreSpec->orSpecification(new IsHidden());
}

$result = new HasExtension($extensions);
if ($ignoreSpec !== null) {
$result = $result->andSpecification(new NotSpecification($ignoreSpec));
}

if ($pathSpec !== null) {
$result = $result->andSpecification($pathSpec);
}

return $result;
}
}
31 changes: 31 additions & 0 deletions packages/filesystem/src/Finder/SpecificationFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\FileSystem\Finder;

use Flyfinder\Specification\SpecificationInterface;
use phpDocumentor\FileSystem\Path;

/**
* Interface for Specifications used to filter the FileSystem.
*/
interface SpecificationFactoryInterface
{
/**
* Creates a SpecificationInterface object based on the ignore and extension parameters.
*
* @param list<string|Path> $paths
* @param list<string> $extensions
*/
public function create(array $paths, Exclude $ignore, array $extensions): SpecificationInterface;
}
90 changes: 90 additions & 0 deletions packages/filesystem/src/Path.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

declare(strict_types=1);

/**
* This file is part of phpDocumentor.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @link https://phpdoc.org
*/

namespace phpDocumentor\FileSystem;

use Stringable;
use Webmozart\Assert\Assert;

use function array_pop;
use function ctype_alpha;
use function explode;
use function implode;
use function parse_url;
use function sprintf;
use function strlen;
use function strspn;

use const PHP_URL_SCHEME;

/**
* Value Object for paths.
* This can be absolute or relative.
*/
final class Path implements Stringable
{
/**
* Initializes the path.
*/
public function __construct(private readonly string $path)
{
Assert::notEmpty(
$path,
sprintf('"%s" is not a valid path', $path),
);
}

/**
* Verifies if another Path object has the same identity as this one.
*/
public function equals(self $otherPath): bool
{
return $this->path === (string) $otherPath;
}

/**
* returns a string representation of the path.
*/
public function __toString(): string
{
return $this->path;
}

/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*/
public static function isAbsolutePath(string $file): bool
{
return strspn($file, '/\\', 0, 1)
|| (strlen($file) > 3 && ctype_alpha($file[0])
&& $file[1] === ':'
&& strspn($file, '/\\', 2, 1)
)
|| parse_url($file, PHP_URL_SCHEME) !== null;
}

public static function dirname(Path $input): self
{
$parts = explode('/', (string) $input);
array_pop($parts);

$path = implode('/', $parts);
if ($path === '') {
return new self('/');
}

return new self($path);
}
}
Loading

0 comments on commit 175f443

Please sign in to comment.