|
|
|
@ -31,34 +31,52 @@ abstract class AbstractAbsolutePath extends AbstractPath implements AbsolutePath
|
|
|
|
|
|
|
|
|
|
// optimize if the same instance |
|
|
|
|
if ($this === $targetPath || $this->components === $targetPath->components) { |
|
|
|
|
return $this->buildRelative(DataTypeHelper::iterableToNewListInstance(['.'])); |
|
|
|
|
return $this->buildRelative(DataTypeHelper::iterableToNewListInstance( |
|
|
|
|
$this->components->count() > 0 && $this->components->top() === '' ? ['.', ''] : ['.'] |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$length = min($this->components->count(), $targetPath->components->count()); |
|
|
|
|
// strip trailing slash |
|
|
|
|
$baseComponents = $this->components; |
|
|
|
|
if ($baseComponents->count() > 0 && $baseComponents->top() === '') { |
|
|
|
|
$baseComponents = clone $baseComponents; // clone when necessary |
|
|
|
|
$baseComponents->pop(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// strip trailing slash |
|
|
|
|
$targetComponents = clone $targetPath->components; // always clone |
|
|
|
|
if ($targetComponents->count() > 0 && $targetComponents->top() === '') { |
|
|
|
|
$targetComponents->pop(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$length = min($baseComponents->count(), $targetComponents->count()); |
|
|
|
|
$equals ??= fn($a, $b) => $a === $b; |
|
|
|
|
|
|
|
|
|
for ($i = 0; $i < $length; $i++) { |
|
|
|
|
if (!$equals($this->components[$i], $targetPath->components[$i])) { |
|
|
|
|
if (!$equals($baseComponents[$i], $targetComponents[$i])) { |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$relativeComponents = clone $targetPath->components; |
|
|
|
|
|
|
|
|
|
// delete $i components from the beginning (common prefix) |
|
|
|
|
for ($j = 0; $j < $i; $j++) { |
|
|
|
|
$relativeComponents->shift(); |
|
|
|
|
$targetComponents->shift(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// add (baseLen - $i) .. elements |
|
|
|
|
$numBaseDiff = $this->components->count() - $i; |
|
|
|
|
$numBaseDiff = $baseComponents->count() - $i; |
|
|
|
|
for ($j = 0; $j < $numBaseDiff; $j++) { |
|
|
|
|
$relativeComponents->unshift('..'); |
|
|
|
|
$targetComponents->unshift('..'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
$relativeComponents->unshift('.'); |
|
|
|
|
// relative marker |
|
|
|
|
$targetComponents->unshift('.'); |
|
|
|
|
// trailing slash |
|
|
|
|
if ($targetPath->components->count() && $targetPath->components->top() === '') { |
|
|
|
|
$targetComponents->push(''); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return $this->buildRelative($relativeComponents); |
|
|
|
|
return $this->buildRelative($targetComponents); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected function buildRelative(\SplDoublyLinkedList $components): RelativePathInterface |
|
|
|
|