Commit 0f3662d3 authored by Anton Smirnov's avatar Anton Smirnov
Browse files

Convert RelativePath

parent fb0a1a34
Loading
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -36,11 +36,11 @@
        }
    },
    "require": {
        "php": "^8.1",
        "php": "^8.5",
        "nikic/iter": "^2.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^10.5",
        "phpunit/phpunit": "^11.5",
        "psy/psysh": "*",
        "sandfox.dev/code-standard": "^1.2025.06.29",
        "squizlabs/php_codesniffer": "*",
+1 −1
Original line number Diff line number Diff line
@@ -6,7 +6,7 @@
         displayDetailsOnTestsThatTriggerDeprecations="true"
         displayDetailsOnPhpunitDeprecations="true"
         executionOrder="random"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd">
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd">
    <testsuites>
        <testsuite name="all">
            <directory>tests</directory>
+27 −28
Original line number Diff line number Diff line
@@ -4,14 +4,11 @@ declare(strict_types=1);

namespace Arokettu\Path;

use Arokettu\Path\Helpers\DataTypeHelper;
use SplDoublyLinkedList;

abstract class AbstractPath implements PathInterface
abstract readonly class AbstractPath implements PathInterface
{
    protected string $prefix;
    /** @var SplDoublyLinkedList<string> */
    protected SplDoublyLinkedList $components;
    /** @var list<string> */
    protected array $components;

    abstract protected function parsePath(string $path, bool $strict): void;

@@ -39,17 +36,18 @@ abstract class AbstractPath implements PathInterface
        }

        if ($path->isRoot()) {
            $newPath = clone $this;
            $newPath->components = DataTypeHelper::iterableToNewListInstance($relativeComponents);
            $newPath = clone($this, [
                'components' => $relativeComponents,
            ]);

            return $newPath;
        }

        $components = clone $this->components;
        $components = $this->components;

        // remove trailing slash
        if ($components->top() === '') {
            $components->pop();
        if (array_last($components) === '') {
            array_pop($components);
        }

        $numComponents = \count($relativeComponents);
@@ -60,24 +58,25 @@ abstract class AbstractPath implements PathInterface

            if (
                $relativeComponents[$i] === '..' &&
                !$components->isEmpty() &&
                $components->top() !== '..' &&
                $components->top() !== '.'
                $components !== [] &&
                array_last($components) !== '..' &&
                array_last($components) !== '.'
            ) {
                $components->pop();
                array_pop($components);
                continue;
            }

            $components->push($relativeComponents[$i]);
            $components[] = $relativeComponents[$i];
        }

        $newPath = clone $this;
        $newPath->components = $this->normalizeHead($components, $strict);
        $newPath = clone($this, [
            'components' => $this->normalizeHead($components, $strict),
        ]);

        return $newPath;
    }

    protected function normalize(array $components): SplDoublyLinkedList
    protected function normalize(array $components): array
    {
        $numComponents = \count($components);

@@ -88,7 +87,7 @@ abstract class AbstractPath implements PathInterface
            }
        }

        $componentsList = new SplDoublyLinkedList();
        $componentsList = [];

        $component = null; // also stores last component ignoring $prevComponent logic
        $prevComponent = null;
@@ -102,29 +101,29 @@ abstract class AbstractPath implements PathInterface
            if (
                $component === '..' &&
                $prevComponent !== '..' && $prevComponent !== null && // leading ..'s
                $componentsList->count() > 0 // beginning of the list
                $componentsList !== [] // beginning of the list
            ) {
                $componentsList->pop();
                array_pop($componentsList);
                continue;
            }

            $componentsList->push($component);
            $componentsList[] = $component;
            $prevComponent = $component;
        }

        // trailing slash logic
        if ($component === '') {
            $componentsList->push('');
            $componentsList[] = '';
        }

        return $componentsList;
    }

    protected function normalizeHead(SplDoublyLinkedList $components, bool $strict): SplDoublyLinkedList
    protected function normalizeHead(array $components, bool $strict): array
    {
        while (!$components->isEmpty()) {
        while ($components !== []) {
            if ($components[0] === '.') {
                $components->shift();
                array_shift($components);
                continue;
            }

@@ -133,7 +132,7 @@ abstract class AbstractPath implements PathInterface
                    throw new \UnexpectedValueException('Relative path went beyond root');
                }

                $components->shift();
                array_shift($components);
                continue;
            }

+10 −13
Original line number Diff line number Diff line
@@ -4,9 +4,7 @@ declare(strict_types=1);

namespace Arokettu\Path;

use SplDoublyLinkedList;

final class RelativePath extends AbstractPath implements RelativePathInterface
final readonly class RelativePath extends AbstractPath implements RelativePathInterface
{
    private bool $windows;

@@ -70,7 +68,7 @@ final class RelativePath extends AbstractPath implements RelativePathInterface
        // absolute-ish relative path
        $isRoot = \strlen($path) > 0 && ($path[0] === '/' || $this->windows && $path[0] === '\\');
        if (!$isRoot) {
            $parsedComponents->unshift('.');
            array_unshift($parsedComponents, '.');
        }

        $this->prefix = '';
@@ -79,7 +77,7 @@ final class RelativePath extends AbstractPath implements RelativePathInterface

    public function isRoot(): bool
    {
        return $this->components->count() === 0 || $this->components[0] !== '.' && $this->components[0] !== '..';
        return $this->components === [] || $this->components[0] !== '.' && $this->components[0] !== '..';
    }

    public function toString(): string
@@ -87,12 +85,11 @@ final class RelativePath extends AbstractPath implements RelativePathInterface
        $directorySeparator = $this->windows ? '\\' : '/';
        $components = $this->components;

        if ($components->count() > 1 && $components[0] === '.' && $components[1] !== '') {
            $components = clone $components;
            $components->shift();
        if (\count($components) > 1 && $components[0] === '.' && $components[1] !== '') {
            array_shift($components);
        }

        $path = \iter\join($directorySeparator, $components);
        $path = implode($directorySeparator, $components);

        if ($this->isRoot()) {
            $path = $directorySeparator . $path;
@@ -101,22 +98,22 @@ final class RelativePath extends AbstractPath implements RelativePathInterface
        return $path;
    }

    protected function normalizeHead(SplDoublyLinkedList $components, bool $strict): SplDoublyLinkedList
    protected function normalizeHead(array $components, bool $strict): array
    {
        if ($this->isRoot()) {
            return parent::normalizeHead($components, $strict);
        }

        while (!$components->isEmpty()) {
        while ($components !== []) {
            if ($components[0] === '.') {
                $components->shift();
                array_shift($components);
                continue;
            }

            break;
        }

        $components->unshift('.');
        array_unshift($components, '.');

        return $components;
    }