• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tempestphp / tempest-framework / 14282305932

05 Apr 2025 01:19PM UTC coverage: 81.133% (+0.2%) from 80.906%
14282305932

Pull #1115

github

web-flow
Merge 722da293d into 90e820853
Pull Request #1115: refactor(view): implement custom html parser

374 of 397 new or added lines in 16 files covered. (94.21%)

6 existing lines in 2 files now uncovered.

11361 of 14003 relevant lines covered (81.13%)

104.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.72
/src/Tempest/View/src/Elements/ElementFactory.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Tempest\View\Elements;
6

7
use Tempest\Container\Container;
8
use Tempest\Core\AppConfig;
9
use Tempest\View\Attributes\PhpAttribute;
10
use Tempest\View\Element;
11
use Tempest\View\Parser\TempestViewCompiler;
12
use Tempest\View\Parser\Token;
13
use Tempest\View\Parser\TokenType;
14
use Tempest\View\ViewComponent;
15
use Tempest\View\ViewConfig;
16
use function Tempest\Support\str;
17

18
final class ElementFactory
19
{
20
    private TempestViewCompiler $compiler;
21

22
    public function __construct(
128✔
23
        private readonly AppConfig $appConfig,
24
        private readonly ViewConfig $viewConfig,
25
        private readonly Container $container,
26
    ) {}
128✔
27

28
    public function setViewCompiler(TempestViewCompiler $compiler): self
121✔
29
    {
30
        $this->compiler = $compiler;
121✔
31

32
        return $this;
121✔
33
    }
34

35
    public function make(Token $token): ?Element
122✔
36
    {
37
        return $this->makeElement(
122✔
38
            token: $token,
122✔
39
            parent: null,
122✔
40
        );
122✔
41
    }
42

43
    private function makeElement(Token $token, ?Element $parent): ?Element
122✔
44
    {
45
        if (
46
            $token->type === TokenType::OPEN_TAG_END ||
122✔
47
                $token->type === TokenType::ATTRIBUTE_NAME ||
122✔
48
                $token->type === TokenType::ATTRIBUTE_VALUE ||
122✔
49
                $token->type === TokenType::SELF_CLOSING_TAG_END
122✔
50
        ) {
NEW
51
            return null;
×
52
        }
53

54
        if ($token->type === TokenType::CONTENT) {
122✔
55
            $text = $token->compile();
97✔
56

57
            if (trim($text) === '') {
97✔
58
                return null;
59✔
59
            }
60

61
            return new TextElement(text: $text);
74✔
62
        }
63

64
        if (! $token->tag || $token->type === TokenType::COMMENT || $token->type === TokenType::PHP) {
114✔
65
            return new RawElement(tag: null, content: $token->compile());
74✔
66
        }
67

68
        $attributes = [];
113✔
69

70
        foreach ($token->htmlAttributes as $name => $value) {
113✔
71
            $name = str($name)
98✔
72
                ->trim()
98✔
73
                ->before('=')
98✔
74
                ->camel()
98✔
75
                ->toString();
98✔
76

77
            $value = str($value)
98✔
78
                ->afterFirst('"')
98✔
79
                ->beforeLast('"')
98✔
80
                ->toString();
98✔
81

82
            $attributes[$name] = $value;
98✔
83
        }
84

85
        foreach ($token->phpAttributes as $index => $content) {
113✔
86
            $attributes[] = new PhpAttribute((string) $index, $content);
1✔
87
        }
88

89
        if ($token->tag === 'code' || $token->tag === 'pre') {
113✔
90
            return new RawElement(
2✔
91
                tag: $token->tag,
2✔
92
                content: $token->compileChildren(),
2✔
93
                attributes: $attributes,
2✔
94
            );
2✔
95
        }
96

97
        if ($viewComponentClass = $this->viewConfig->viewComponents[$token->tag] ?? null) {
112✔
98
            if (! ($viewComponentClass instanceof ViewComponent)) {
71✔
99
                $viewComponentClass = $this->container->get($viewComponentClass);
28✔
100
            }
101

102
            $element = new ViewComponentElement(
71✔
103
                environment: $this->appConfig->environment,
71✔
104
                compiler: $this->compiler,
71✔
105
                viewComponent: $viewComponentClass,
71✔
106
                attributes: $attributes,
71✔
107
            );
71✔
108
        } elseif ($token->tag === 'x-template') {
103✔
109
            $element = new TemplateElement(
1✔
110
                attributes: $attributes,
1✔
111
            );
1✔
112
        } elseif ($token->tag === 'x-slot') {
103✔
113
            $element = new SlotElement(
6✔
114
                name: $token->getAttribute('name') ?? 'slot',
6✔
115
                attributes: $attributes,
6✔
116
            );
6✔
117
        } else {
118
            $element = new GenericElement(
102✔
119
                tag: $token->tag,
102✔
120
                attributes: $attributes,
102✔
121
            );
102✔
122
        }
123

124
        $children = [];
112✔
125

126
        foreach ($token->children as $child) {
112✔
127
            $childElement = $this->clone()->makeElement(
78✔
128
                token: $child,
78✔
129
                parent: $parent,
78✔
130
            );
78✔
131

132
            if ($childElement === null) {
78✔
133
                continue;
38✔
134
            }
135

136
            $children[] = $childElement;
78✔
137
        }
138

139
        $element->setChildren($children);
112✔
140

141
        return $element;
112✔
142
    }
143

144
    private function clone(): self
78✔
145
    {
146
        return clone $this;
78✔
147
    }
148
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc