Passed
Push — main ( b151e0...61a7fd )
by Colin
03:30 queued 01:20
created

AttributesHelper::parseAttributes()   C

Complexity

Conditions 14
Paths 16

Size

Total Lines 65
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 30
CRAP Score 14.0478

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 14
eloc 32
c 2
b 0
f 0
nc 16
nop 1
dl 0
loc 65
ccs 30
cts 32
cp 0.9375
crap 14.0478
rs 6.2666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the league/commonmark package.
5
 *
6
 * (c) Colin O'Dell <[email protected]>
7
 * (c) 2015 Martin Hasoň <[email protected]>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
declare(strict_types=1);
14
15
namespace League\CommonMark\Extension\Attributes\Util;
16
17
use League\CommonMark\Node\Node;
18
use League\CommonMark\Parser\Cursor;
19
use League\CommonMark\Util\RegexHelper;
20
21
/**
22
 * @internal
23
 */
24
final class AttributesHelper
25
{
26
    private const SINGLE_ATTRIBUTE = '\s*([.#][_a-z0-9-]+|' . RegexHelper::PARTIAL_ATTRIBUTENAME . RegexHelper::PARTIAL_ATTRIBUTEVALUESPEC . ')\s*';
27
    private const ATTRIBUTE_LIST   = '/^{:?(' . self::SINGLE_ATTRIBUTE . ')+}/i';
28
29
    /**
30
     * @return array<string, mixed>
31
     */
32 94
    public static function parseAttributes(Cursor $cursor): array
33
    {
34 94
        $state = $cursor->saveState();
35 94
        $cursor->advanceToNextNonSpaceOrNewline();
36
37
        // Quick check to see if we might have attributes
38 94
        if ($cursor->getCharacter() !== '{') {
39 14
            $cursor->restoreState($state);
40
41 14
            return [];
42
        }
43
44
        // Attempt to match the entire attribute list expression
45
        // While this is less performant than checking for '{' now and '}' later, it simplifies
46
        // matching individual attributes since they won't need to look ahead for the closing '}'
47
        // while dealing with the fact that attributes can technically contain curly braces.
48
        // So we'll just match the start and end braces up front.
49 92
        $attributeExpression = $cursor->match(self::ATTRIBUTE_LIST);
50 92
        if ($attributeExpression === null) {
51 8
            $cursor->restoreState($state);
52
53 8
            return [];
54
        }
55
56
        // Trim the leading '{' or '{:' and the trailing '}'
57 86
        $attributeExpression = \ltrim(\substr($attributeExpression, 1, -1), ':');
58 86
        $attributeCursor     = new Cursor($attributeExpression);
59
60
        /** @var array<string, mixed> $attributes */
61 86
        $attributes = [];
62 86
        while ($attribute = \trim((string) $attributeCursor->match('/^' . self::SINGLE_ATTRIBUTE . '/i'))) {
63 86
            if ($attribute[0] === '#') {
64 36
                $attributes['id'] = \substr($attribute, 1);
65
66 36
                continue;
67
            }
68
69 60
            if ($attribute[0] === '.') {
70 20
                $attributes['class'][] = \substr($attribute, 1);
71
72 20
                continue;
73
            }
74
75 48
            [$name, $value] = \explode('=', $attribute, 2);
76
77 48
            $first = $value[0];
78 48
            $last  = \substr($value, -1);
79 48
            if (($first === '"' && $last === '"') || ($first === "'" && $last === "'") && \strlen($value) > 1) {
80 30
                $value = \substr($value, 1, -1);
81
            }
82
83 48
            if (\strtolower(\trim($name)) === 'class') {
84
                foreach (\array_filter(\explode(' ', \trim($value))) as $class) {
85
                    $attributes['class'][] = $class;
86
                }
87
            } else {
88 48
                $attributes[\trim($name)] = \trim($value);
89
            }
90
        }
91
92 86
        if (isset($attributes['class'])) {
93 20
            $attributes['class'] = \implode(' ', (array) $attributes['class']);
94
        }
95
96 86
        return $attributes;
97
    }
98
99
    /**
100
     * @param Node|array<string, mixed> $attributes1
101
     * @param Node|array<string, mixed> $attributes2
102
     *
103
     * @return array<string, mixed>
104
     */
105 34
    public static function mergeAttributes($attributes1, $attributes2): array
106
    {
107 34
        $attributes = [];
108 34
        foreach ([$attributes1, $attributes2] as $arg) {
109 34
            if ($arg instanceof Node) {
110 28
                $arg = $arg->data->get('attributes');
111
            }
112
113
            /** @var array<string, mixed> $arg */
114 34
            $arg = (array) $arg;
115 34
            if (isset($arg['class'])) {
116 30
                if (\is_string($arg['class'])) {
117 30
                    $arg['class'] = \array_filter(\explode(' ', \trim($arg['class'])));
118
                }
119
120 30
                foreach ($arg['class'] as $class) {
121 30
                    $attributes['class'][] = $class;
122
                }
123
124 30
                unset($arg['class']);
125
            }
126
127 34
            $attributes = \array_merge($attributes, $arg);
128
        }
129
130 34
        if (isset($attributes['class'])) {
131 30
            $attributes['class'] = \implode(' ', $attributes['class']);
132
        }
133
134 34
        return $attributes;
135
    }
136
}
137