Completed
Push — master ( f38e95...1522e3 )
by Martin
03:50
created

AttributesProcessor::getNext()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 0
cts 0
cp 0
rs 9.9332
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 20
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This is part of the webuni/commonmark-attributes-extension package.
7
 *
8
 * (c) Martin Hasoň <[email protected]>
9
 * (c) Webuni s.r.o. <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Webuni\CommonMark\AttributesExtension;
16
17
use League\CommonMark\Block\Element\AbstractBlock;
18
use League\CommonMark\Block\Element\Document;
19
use League\CommonMark\Block\Element\FencedCode;
20
use League\CommonMark\Block\Element\ListBlock;
21
use League\CommonMark\Block\Element\ListItem;
22
use League\CommonMark\Inline\Element\AbstractInline;
23
use League\CommonMark\Node\Node;
24
25
final class AttributesProcessor
26
{
27
    private const DIRECTION_PREFIX = 'prefix';
28 5
29
    private const DIRECTION_SUFFIX = 'suffix';
30 5
31 5
    public function processDocument(Document $document): void
32 5
    {
33
        $walker = $document->walker();
34 5
        while ($event = $walker->next()) {
35 5
            $node = $event->getNode();
36
            if (!$node instanceof AttributesInline && ($event->isEntering() || !$node instanceof Attributes)) {
37
                continue;
38 5
            }
39
40 5
            list($target, $direction) = $this->findTargetAndDirection($node);
41 5
42 1
            if ($target instanceof Node) {
43
                $parent = $target->parent();
44
                if ($parent instanceof ListItem && $parent->parent() instanceof ListBlock && $parent->parent()->isTight()) {
45 5
                    $target = $parent;
46 4
                }
47
48 3
                if (self::DIRECTION_SUFFIX === $direction) {
49
                    $attributes = AttributesUtils::merge($target, $node->getAttributes());
50
                } else {
51 5
                    $attributes = AttributesUtils::merge($node->getAttributes(), $target);
52
                }
53
54 5
                if ($target instanceof AbstractBlock || $target instanceof AbstractInline) {
55 3
                    $target->data['attributes'] = $attributes;
56
                }
57
            }
58 5
59
            if ($node instanceof AbstractBlock && $node->endsWithBlankLine() && $node->next() && $node->previous()) {
60 5
                $previous = $node->previous();
61
                if ($previous instanceof AbstractBlock) {
62 5
                    $previous->setLastLineBlank(true);
63
                }
64 5
            }
65 5
66 5
            $node->detach();
67 5
        }
68 5
    }
69 5
70
    private function findTargetAndDirection(Node $node): array
71 5
    {
72 1
        $target = null;
73 1
        $direction = null;
74
        $previous = $next = $node;
75 1
        while (true) {
76
            $previous = $this->getPrevious($previous);
77
            $next = $this->getNext($next);
78 5
79 4
            if (null === $previous && null === $next) {
80 4
                if (!$node->parent() instanceof FencedCode) {
81
                    $target = $node->parent();
82 4
                    $direction = self::DIRECTION_SUFFIX;
83
                }
84
85 3
                break;
86 3
            }
87 3
88
            if ($node instanceof AttributesInline && (null === $previous || ($previous instanceof AbstractInline && $node->isBlock()))) {
89 3
                continue;
90
            }
91
92
            if (null !== $previous && !$this->isAttributesNode($previous)) {
93 5
                $target = $previous;
94
                $direction = self::DIRECTION_SUFFIX;
95
96 5
                break;
97
            }
98 5
99
            if (null !== $next && !$this->isAttributesNode($next)) {
100 5
                $target = $next;
101 2
                $direction = self::DIRECTION_PREFIX;
102
103
                break;
104 5
            }
105
        }
106
107 5
        return [$target, $direction];
108
    }
109 5
110 5
    private function getPrevious(Node $node = null): ?Node
111
    {
112
        $previous = $node instanceof Node ? $node->previous() : null;
113
114
        if ($previous instanceof AbstractBlock && $previous->endsWithBlankLine()) {
115
            $previous = null;
116
        }
117
118
        return $previous;
119
    }
120
121
    private function getNext(Node $node = null): ?Node
122
    {
123
        $next = $node instanceof Node ? $node->next() : null;
124
125
        if ($node instanceof AbstractBlock && $node->endsWithBlankLine()) {
126
            $next = null;
127
        }
128
129
        return $next;
130
    }
131
132
    private function isAttributesNode(Node $node): bool
133
    {
134
        return $node instanceof Attributes || $node instanceof AttributesInline;
135
    }
136
}
137