Skip to content

Commit 488645f

Browse files
committed
Methods to mutate \LastDragon_ru\LaraASP\Documentator\Editor\Editor moved into new \LastDragon_ru\LaraASP\Documentator\Editor\Mutators\Mutator class.
1 parent e9bc2b9 commit 488645f

File tree

4 files changed

+353
-282
lines changed

4 files changed

+353
-282
lines changed

packages/documentator/src/Editor/Editor.php

+7-183
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,20 @@
33
namespace LastDragon_ru\LaraASP\Documentator\Editor;
44

55
use LastDragon_ru\LaraASP\Documentator\Editor\Mutators\Extractor;
6+
use LastDragon_ru\LaraASP\Documentator\Editor\Mutators\Mutator;
67
use LastDragon_ru\LaraASP\Documentator\Utils\Text;
78
use Override;
89
use Stringable;
910

10-
use function array_merge;
11-
use function array_push;
12-
use function array_reverse;
13-
use function array_slice;
14-
use function array_splice;
15-
use function array_values;
16-
use function count;
1711
use function implode;
1812
use function is_string;
19-
use function mb_rtrim;
20-
use function mb_substr;
21-
use function usort;
22-
23-
use const PHP_INT_MAX;
2413

2514
readonly class Editor implements Stringable {
2615
/**
2716
* @var list<string>
2817
*/
2918
protected array $lines;
19+
protected Mutator $mutator;
3020
protected Extractor $extractor;
3121

3222
/**
@@ -38,6 +28,7 @@ final public function __construct(
3828
protected string $endOfLine = "\n",
3929
) {
4030
$this->lines = is_string($content) ? Text::getLines($content) : $content;
31+
$this->mutator = new Mutator();
4132
$this->extractor = new Extractor();
4233
}
4334

@@ -59,181 +50,14 @@ public function extract(iterable $locations): static {
5950
}
6051

6152
/**
62-
* @param iterable<array-key, array{iterable<array-key, Coordinate>, ?string}> $changes
53+
* @param iterable<mixed, array{iterable<mixed, Coordinate>, ?string}> $changes
6354
*
6455
* @return new<static>
6556
*/
6657
public function mutate(iterable $changes): static {
67-
// Modify
68-
$lines = $this->lines;
69-
$changes = $this->prepare($changes);
70-
$changes = $this->removeOverlaps($changes);
71-
$changes = $this->expand($changes);
72-
73-
foreach ($changes as [$coordinate, $text]) {
74-
// Append?
75-
if ($coordinate->line === PHP_INT_MAX) {
76-
array_push($lines, ...$text);
77-
continue;
78-
}
79-
80-
// Change
81-
$number = $coordinate->line - $this->startLine;
82-
$line = $lines[$number] ?? '';
83-
$count = count($text);
84-
$prefix = mb_substr($line, 0, $coordinate->offset);
85-
$suffix = $coordinate->length !== null
86-
? mb_substr($line, $coordinate->offset + $coordinate->length)
87-
: '';
88-
$padding = mb_substr($line, 0, $coordinate->padding);
89-
90-
if ($count > 1) {
91-
$insert = [];
92-
93-
for ($t = 0; $t < $count; $t++) {
94-
$insert[] = match (true) {
95-
$t === 0 => mb_rtrim($prefix.$text[$t]),
96-
$t === $count - 1 => mb_rtrim($padding.$text[$t].$suffix),
97-
default => mb_rtrim($padding.$text[$t]),
98-
};
99-
}
100-
101-
array_splice($lines, $number, 1, $insert);
102-
} elseif ($count === 1) {
103-
$lines[$number] = mb_rtrim($prefix.$text[0].$suffix);
104-
} elseif (($prefix !== '' && $prefix !== $padding) || $suffix !== '') {
105-
$lines[$number] = mb_rtrim($prefix.$suffix);
106-
} else {
107-
unset($lines[$number]);
108-
}
109-
}
110-
111-
// Return
112-
return new static(array_values($lines), $this->startLine, $this->endOfLine);
113-
}
114-
115-
/**
116-
* @param iterable<array-key, array{iterable<array-key, Coordinate>, ?string}> $changes
117-
*
118-
* @return list<array{list<Coordinate>, ?string}>
119-
*/
120-
protected function prepare(iterable $changes): array {
121-
$prepared = [];
122-
123-
foreach ($changes as [$location, $text]) {
124-
$coordinates = [];
125-
126-
foreach ($location as $coordinate) {
127-
$coordinates[] = $coordinate;
128-
}
129-
130-
if ($coordinates !== []) {
131-
$prepared[] = [$coordinates, $text];
132-
}
133-
}
134-
135-
return array_reverse($prepared);
136-
}
137-
138-
/**
139-
* @param array<int, array{list<Coordinate>, ?string}> $changes
140-
*
141-
* @return list<array{Coordinate, list<string>}>
142-
*/
143-
protected function expand(array $changes): array {
144-
$expanded = [];
145-
$append = [];
146-
$sort = static function (Coordinate $a, Coordinate $b): int {
147-
$result = $a->line <=> $b->line;
148-
$result = $result === 0
149-
? $a->offset <=> $b->offset
150-
: $result;
151-
152-
return $result;
153-
};
154-
155-
foreach ($changes as [$coordinates, $text]) {
156-
$text = match (true) {
157-
$text === null => [],
158-
$text === '' => [''],
159-
default => Text::getLines($text),
160-
};
58+
$mutated = ($this->mutator)($this->lines, $changes, $this->startLine);
59+
$editor = new static($mutated, $this->startLine, $this->endOfLine);
16160

162-
usort($coordinates, $sort);
163-
164-
for ($i = 0, $c = count($coordinates); $i < $c; $i++) {
165-
$line = $i === $c - 1 ? array_slice($text, $i) : (array) ($text[$i] ?? null);
166-
167-
if ($coordinates[$i]->line === PHP_INT_MAX) {
168-
$append[] = [$coordinates[$i], $line];
169-
} else {
170-
$expanded[] = [$coordinates[$i], $line];
171-
}
172-
}
173-
}
174-
175-
usort($expanded, static fn ($a, $b) => -$sort($a[0], $b[0]));
176-
177-
return array_merge($expanded, array_reverse($append));
178-
}
179-
180-
/**
181-
* @param list<array{list<Coordinate>, ?string}> $changes
182-
*
183-
* @return array<int, array{list<Coordinate>, ?string}>
184-
*/
185-
protected function removeOverlaps(array $changes): array {
186-
$used = [];
187-
188-
foreach ($changes as $key => [$coordinates]) {
189-
$lines = [];
190-
191-
foreach ($coordinates as $coordinate) {
192-
$lines[$coordinate->line][] = $coordinate;
193-
194-
if ($this->isOverlapped($used, $coordinate)) {
195-
$lines = [];
196-
break;
197-
}
198-
}
199-
200-
if ($lines !== []) {
201-
foreach ($lines as $line => $coords) {
202-
$used[$line] = array_merge($used[$line] ?? [], $coords);
203-
}
204-
} else {
205-
unset($changes[$key]);
206-
}
207-
}
208-
209-
// Return
210-
return $changes;
211-
}
212-
213-
/**
214-
* @param array<int, array<int, Coordinate>> $coordinates
215-
*/
216-
private function isOverlapped(array $coordinates, Coordinate $coordinate): bool {
217-
// Append?
218-
if ($coordinate->line === PHP_INT_MAX) {
219-
return false;
220-
}
221-
222-
// Check
223-
$overlapped = false;
224-
225-
foreach ($coordinates[$coordinate->line] ?? [] as $c) {
226-
$aStart = $c->offset;
227-
$aEnd = $aStart + ($c->length ?? PHP_INT_MAX) - 1;
228-
$bStart = $coordinate->offset;
229-
$bEnd = $bStart + ($coordinate->length ?? PHP_INT_MAX) - 1;
230-
$overlapped = !($bEnd < $aStart || $bStart > $aEnd);
231-
232-
if ($overlapped) {
233-
break;
234-
}
235-
}
236-
237-
return $overlapped;
61+
return $editor;
23862
}
23963
}

packages/documentator/src/Editor/EditorTest.php

-99
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,10 @@
22

33
namespace LastDragon_ru\LaraASP\Documentator\Editor;
44

5-
use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Append;
65
use LastDragon_ru\LaraASP\Documentator\Editor\Locations\Location;
76
use LastDragon_ru\LaraASP\Documentator\Testing\Package\TestCase;
8-
use Override;
97
use PHPUnit\Framework\Attributes\CoversClass;
108

11-
use function array_values;
12-
use function iterator_to_array;
13-
149
use const PHP_INT_MAX;
1510

1611
/**
@@ -125,98 +120,4 @@ public function getLines(): array {
125120
self::assertEquals($lines, $editor->getLines());
126121
self::assertSame($expected, $actual->getLines());
127122
}
128-
129-
public function testPrepare(): void {
130-
$editor = new readonly class(['L1', 'L2']) extends Editor {
131-
/**
132-
* @inheritDoc
133-
*/
134-
#[Override]
135-
public function prepare(iterable $changes): array {
136-
return parent::prepare($changes);
137-
}
138-
};
139-
$changes = [
140-
[new Location(10, 10, 15, 10), 'a'],
141-
[new Location(10, 10, 10, null), 'b'],
142-
[new Location(12, 15, 5, 10), 'c'],
143-
];
144-
$expected = [
145-
[iterator_to_array(new Location(12, 15, 5, 10)), 'c'],
146-
[iterator_to_array(new Location(10, 10, 10, null)), 'b'],
147-
[iterator_to_array(new Location(10, 10, 15, 10)), 'a'],
148-
];
149-
150-
self::assertEquals($expected, $editor->prepare($changes));
151-
}
152-
153-
public function testRemoveOverlaps(): void {
154-
$editor = new readonly class([]) extends Editor {
155-
/**
156-
* @inheritDoc
157-
*/
158-
#[Override]
159-
public function removeOverlaps(array $changes): array {
160-
return parent::removeOverlaps($changes);
161-
}
162-
};
163-
$changes = [
164-
0 => [array_values(iterator_to_array(new Location(18, 18, 5, 10))), 'a'],
165-
1 => [array_values(iterator_to_array(new Location(17, 17, 11, 10))), 'b'],
166-
2 => [array_values(iterator_to_array(new Location(17, 17, 5, 10))), 'c'],
167-
3 => [array_values(iterator_to_array(new Location(14, 15, 5, 10))), 'd'],
168-
4 => [array_values(iterator_to_array(new Location(12, 15, 5, 10))), 'e'],
169-
5 => [array_values(iterator_to_array(new Location(10, 10, 10, null))), 'f'],
170-
6 => [array_values(iterator_to_array(new Location(10, 10, 15, 10))), 'g'],
171-
7 => [array_values(iterator_to_array(new Location(9, 9, 39, 11))), 'h'],
172-
8 => [array_values(iterator_to_array(new Location(9, 9, 50, null))), 'i'],
173-
9 => [array_values(iterator_to_array(new Location(9, 9, 40, 10))), 'j'],
174-
10 => [array_values(iterator_to_array(new Location(PHP_INT_MAX, PHP_INT_MAX))), 'k'],
175-
11 => [array_values(iterator_to_array(new Append())), 'l'],
176-
];
177-
$expected = [
178-
0 => [iterator_to_array(new Location(18, 18, 5, 10)), 'a'],
179-
1 => [iterator_to_array(new Location(17, 17, 11, 10)), 'b'],
180-
3 => [iterator_to_array(new Location(14, 15, 5, 10)), 'd'],
181-
5 => [iterator_to_array(new Location(10, 10, 10, null)), 'f'],
182-
7 => [iterator_to_array(new Location(9, 9, 39, 11)), 'h'],
183-
8 => [iterator_to_array(new Location(9, 9, 50, null)), 'i'],
184-
10 => [iterator_to_array(new Location(PHP_INT_MAX, PHP_INT_MAX)), 'k'],
185-
11 => [iterator_to_array(new Append()), 'l'],
186-
];
187-
188-
self::assertEquals($expected, $editor->removeOverlaps($changes));
189-
}
190-
191-
public function testExpand(): void {
192-
$editor = new readonly class([]) extends Editor {
193-
/**
194-
* @inheritDoc
195-
*/
196-
#[Override]
197-
public function expand(array $changes): array {
198-
return parent::expand($changes);
199-
}
200-
};
201-
$changes = [
202-
[array_values(iterator_to_array(new Location(PHP_INT_MAX, PHP_INT_MAX))), "new line aa\nnew line ab"],
203-
[array_values(iterator_to_array(new Location(6, 6, 5, 10, 2))), "text aa\ntext ab"],
204-
[array_values(iterator_to_array(new Location(4, 5, 5, 5, 1))), "text ba\ntext bb"],
205-
[array_values(iterator_to_array(new Location(2, 3, 5, null))), 'text c'],
206-
[array_values(iterator_to_array(new Location(1, 1, 5, 10))), "text da\ntext db\ntext dc"],
207-
[array_values(iterator_to_array(new Append())), "new line ba\nnew line bb"],
208-
];
209-
$expected = [
210-
[new Coordinate(6, 7, 10, 2), ['text aa', 'text ab']],
211-
[new Coordinate(5, 1, 5, 1), ['text bb']],
212-
[new Coordinate(4, 6, null, 1), ['text ba']],
213-
[new Coordinate(3, 0, null, 0), []],
214-
[new Coordinate(2, 5, null, 0), ['text c']],
215-
[new Coordinate(1, 5, 10, 0), ['text da', 'text db', 'text dc']],
216-
[new Coordinate(PHP_INT_MAX, 0, null, 0), ['new line ba', 'new line bb']],
217-
[new Coordinate(PHP_INT_MAX, 0, null, 0), ['new line aa', 'new line ab']],
218-
];
219-
220-
self::assertEquals($expected, $editor->expand($changes));
221-
}
222123
}

0 commit comments

Comments
 (0)