HTMLSyntax::handle()   D
last analyzed

Complexity

Conditions 24
Paths 19

Size

Total Lines 103
Code Lines 66

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 53
CRAP Score 24.0886

Importance

Changes 0
Metric Value
eloc 66
dl 0
loc 103
ccs 53
cts 56
cp 0.9464
rs 4.1666
c 0
b 0
f 0
cc 24
nc 19
nop 3
crap 24.0886

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
declare(strict_types=1);
4
5
namespace Spiral\Stempler\Parser\Syntax;
6
7
use Spiral\Stempler\Exception\SyntaxException;
8
use Spiral\Stempler\Lexer\Grammar\HTMLGrammar;
9
use Spiral\Stempler\Lexer\Token;
10
use Spiral\Stempler\Node\HTML\Attr;
11
use Spiral\Stempler\Node\HTML\Nil;
12
use Spiral\Stempler\Node\HTML\Tag;
13
use Spiral\Stempler\Node\HTML\Verbatim;
14
use Spiral\Stempler\Node\Mixin;
15
use Spiral\Stempler\Node\Raw;
16
use Spiral\Stempler\Parser;
17
use Spiral\Stempler\Parser\Assembler;
18
use Spiral\Stempler\Parser\SyntaxInterface;
19
20
/**
21
 * HTML tags and attributes.
22
 */
23
final class HTMLSyntax implements SyntaxInterface
24
{
25
    use Parser\Syntax\Traits\MixinTrait;
0 ignored issues
show
introduced by
The trait Spiral\Stempler\Parser\Syntax\Traits\MixinTrait requires some properties which are not provided by Spiral\Stempler\Parser\Syntax\HTMLSyntax: $tokens, $type, $content
Loading history...
26
27
    // list of tags which are closed automatically (http://xahlee.info/js/html5_non-closing_tag.html)
28
    private const VOID_TAGS = [
29
        'area',
30
        'base',
31
        'br',
32
        'col',
33
        'embed',
34
        'hr',
35
        'img',
36
        'input',
37
        'link',
38
        'meta',
39
        'param',
40
        'source',
41
        'track',
42
        'wbr',
43
    ];
44
45
    // list of attributes which define verbatim blocks (https://www.w3schools.com/tags/ref_eventattributes.asp)
46
    private const VERBATIM_ATTRIBUTES = [
47
        'style',
48
        'on*',
49
    ];
50
51
    private ?Tag $node = null;
52
    private ?Token $token = null;
53
    private ?Attr $attr = null;
54
55 108
    public function handle(Parser $parser, Assembler $asm, Token $token): void
56
    {
57 108
        switch ($token->type) {
58
            case HTMLGrammar::TYPE_OPEN:
59
            case HTMLGrammar::TYPE_OPEN_SHORT:
60 108
                $this->node = new Tag(new Parser\Context($token, $parser->getPath()));
61 108
                $this->token = $token;
62
63 108
                break;
64
65
            case HTMLGrammar::TYPE_KEYWORD:
66 108
                if ($this->node->name === null) {
67 108
                    $this->node->name = $this->parseToken($parser, $token);
68 108
                    return;
69
                }
70
71 85
                if ($this->attr !== null && !$this->attr->value instanceof Nil) {
72 1
                    $this->attr->value = $this->parseToken($parser, $token);
73 1
                    $this->attr = null;
74 1
                    break;
75
                }
76
77 85
                $this->attr = new Attr(
78 85
                    $this->parseToken($parser, $token),
0 ignored issues
show
Bug introduced by
It seems like $this->parseToken($parser, $token) can also be of type Spiral\Stempler\Node\Raw; however, parameter $name of Spiral\Stempler\Node\HTML\Attr::__construct() does only seem to accept Spiral\Stempler\Node\Mixin|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

78
                    /** @scrutinizer ignore-type */ $this->parseToken($parser, $token),
Loading history...
79 85
                    new Nil(),
80 85
                    new Parser\Context($token, $parser->getPath()),
81 85
                );
82
83 85
                $this->node->attrs[] = $this->attr;
84 85
                break;
85
86
            case HTMLGrammar::TYPE_EQUAL:
87 84
                if ($this->attr === null) {
88
                    throw new SyntaxException('unexpected attribute token', $token);
89
                }
90
91
                // expect the value
92 84
                $this->attr->value = null;
93 84
                break;
94
95
            case HTMLGrammar::TYPE_ATTRIBUTE:
96 84
                if ($this->attr === null) {
97
                    throw new SyntaxException('unexpected attribute token', $token);
98
                }
99
100
                if (
101 84
                    \is_string($this->attr->name)
102
                    && (
103 84
                        \str_starts_with($this->attr->name, 'on')
104 84
                        || \in_array($this->attr->name, self::VERBATIM_ATTRIBUTES, true)
105
                    )
106
                ) {
107 5
                    $this->attr->value = $this->parseVerbatim($parser, $token);
108
                } else {
109 81
                    $this->attr->value = $this->parseToken($parser, $token);
110
                }
111
112 84
                $this->attr = null;
113 84
                break;
114
115
            case HTMLGrammar::TYPE_CLOSE_SHORT:
116 67
                $this->node->void = true;
117 67
                $asm->push($this->node);
0 ignored issues
show
Bug introduced by
It seems like $this->node can also be of type null; however, parameter $node of Spiral\Stempler\Parser\Assembler::push() does only seem to accept Spiral\Stempler\Node\NodeInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

117
                $asm->push(/** @scrutinizer ignore-type */ $this->node);
Loading history...
118 67
                $this->flush();
119 67
                break;
120
121
            case HTMLGrammar::TYPE_CLOSE:
122 99
                if ($this->token->type == HTMLGrammar::TYPE_OPEN_SHORT) {
123 95
                    if (!$asm->getNode() instanceof Tag || $asm->getNode()->name !== $this->node->name) {
124
                        /**
125
                         * TODO issue #767
126
                         * @link https://github.com/spiral/framework/issues/767
127
                         * @psalm-suppress NoInterfaceProperties
128
                         */
129 4
                        throw new SyntaxException(
130 4
                            "Invalid closing tag `{$this->node->name}`, expected `{$asm->getNode()->name}`",
131 4
                            $this->token,
0 ignored issues
show
Bug introduced by
It seems like $this->token can also be of type null; however, parameter $token of Spiral\Stempler\Exceptio...xception::__construct() does only seem to accept Spiral\Stempler\Lexer\Token, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

131
                            /** @scrutinizer ignore-type */ $this->token,
Loading history...
132 4
                        );
133
                    }
134
135 93
                    $asm->close();
136 99
                } elseif (\in_array($this->node->name, self::VOID_TAGS)) {
137 2
                    $this->node->void = true;
138 2
                    $asm->push($this->node);
139
                } else {
140 97
                    $asm->open($this->node, 'nodes');
0 ignored issues
show
Bug introduced by
It seems like $this->node can also be of type null; however, parameter $node of Spiral\Stempler\Parser\Assembler::open() does only seem to accept Spiral\Stempler\Node\NodeInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

140
                    $asm->open(/** @scrutinizer ignore-type */ $this->node, 'nodes');
Loading history...
141
                }
142 99
                $this->flush();
143
144 99
                break;
145
146
            case HTMLGrammar::TYPE_VERBATIM:
147 3
                $asm->push($this->parseVerbatim($parser, $token));
148 3
                break;
149
150
            default:
151 87
                if ($asm->getNode() instanceof Mixin || $asm->getNode() instanceof Verbatim) {
152 45
                    $node = $this->parseToken($parser, $token);
153 45
                    if (\is_string($node)) {
154
                        $node = new Raw($node, new Parser\Context($token, $parser->getPath()));
155
                    }
156
157 45
                    $asm->push($node);
0 ignored issues
show
Bug introduced by
It seems like $node can also be of type string; however, parameter $node of Spiral\Stempler\Parser\Assembler::push() does only seem to accept Spiral\Stempler\Node\NodeInterface, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

157
                    $asm->push(/** @scrutinizer ignore-type */ $node);
Loading history...
158
                }
159
        }
160
    }
161
162
    /**
163
     * Flush open nodes and tokens.
164
     */
165 108
    private function flush(): void
166
    {
167 108
        $this->node = null;
168 108
        $this->token = null;
169 108
        $this->attr = null;
170
    }
171
172 8
    private function parseVerbatim(Parser $parser, Token $token): Verbatim
173
    {
174 8
        $verbatim = new Verbatim(new Parser\Context($token, $parser->getPath()));
175
176 8
        if ($token->tokens === []) {
177 3
            if ($token->content) {
178 3
                $verbatim->nodes[] = $token->content;
179
            }
180
        } else {
181
            /**
182
             * TODO issue #767
183
             * @link https://github.com/spiral/framework/issues/767
184
             * @psalm-suppress InvalidArgument
185
             */
186 5
            $parser->parseTokens(
187 5
                new Assembler($verbatim, 'nodes'),
188 5
                $token->tokens,
189 5
            );
190
        }
191
192 8
        return $verbatim;
193
    }
194
}
195