Passed
Push — master ( 0efe92...619655 )
by Caen
03:42 queued 17s
created

ConsoleOutput::formatLineForOutput()   B

Complexity

Conditions 9
Paths 7

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 9
eloc 12
c 3
b 0
f 0
nc 7
nop 1
dl 0
loc 20
rs 8.0555
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Hyde\RealtimeCompiler;
6
7
use Closure;
8
use Hyde\Hyde;
9
use Illuminate\Support\Str;
10
use Illuminate\Support\Carbon;
11
12
use function max;
13
use function str;
14
use function trim;
15
use function strlen;
16
use function substr;
17
use function sprintf;
18
use function str_repeat;
19
use function str_replace;
20
use function str_contains;
21
use function Termwind\render;
22
23
class ConsoleOutput
24
{
25
    protected bool $verbose;
26
27
    public static function printStartMessage(string $host, int $port): void
28
    {
29
        $title = 'HydePHP Realtime Compiler';
30
        $version = ' v'.Hyde::version();
31
32
        $url = sprintf('http://%s:%d', $host, $port);
33
34
        $width = max(strlen("$title $version"), strlen("Listening on $url") + 1) + 1;
35
        $spacing = str_repeat('&nbsp;', $width);
36
        $lines = str_repeat('─', $width);
37
38
        $line1 = '&nbsp;'.sprintf('<span class="text-blue-500">%s</span>&nbsp;<span class="text-gray">%s</span>', $title, $version).str_repeat('&nbsp;', $width - strlen("$title $version"));
39
        $line2 = '&nbsp;'.sprintf('<span class="text-white">Listening on </span>&nbsp;<a href="%s" class="text-yellow-500">%s</a>', $url, $url).str_repeat('&nbsp;', $width - strlen("Listening on $url") - 1);
40
        render(<<<HTML
41
<div class="text-green-500">
42
<br>
43
&nbsp;╭{$lines}╮<br>
44
&nbsp;│{$spacing}│<br>
45
&nbsp;│{$line1}│<br>
46
&nbsp;│{$spacing}│<br>
47
&nbsp;│{$line2}│<br>
48
&nbsp;│{$spacing}│<br>
49
&nbsp;╰{$lines}╯
50
<br>
51
</div>
52
HTML);
53
    }
54
55
    public static function getFormatter(bool $verbose): Closure
56
    {
57
        $console = (new static($verbose));
58
59
        return function (string $type, string $line) use ($console): void {
60
            $console->handleOutput($line);
61
        };
62
    }
63
64
    /** @experimental */
65
    public static function printMessage(string $message, string $context): void
66
    {
67
        $consoleOutput = new \Symfony\Component\Console\Output\ConsoleOutput();
68
        $consoleOutput->writeln(sprintf('%s [%s]', $message, $context));
69
    }
70
71
    public function __construct(bool $verbose = false)
72
    {
73
        $this->verbose = $verbose;
74
    }
75
76
    protected function handleOutput(string $buffer): void
77
    {
78
        str($buffer)->trim()->explode("\n")->each(function (string $line): void {
79
            $line = $this->formatLineForOutput($line);
80
81
            if ($line !== null) {
82
                render($line);
83
            }
84
        });
85
    }
86
87
    protected function formatLineForOutput(string $line): ?string
88
    {
89
        if (str_contains($line, 'Development Server (http:')) {
90
            return $this->formatServerStartedLine($line);
91
        }
92
        if (str_contains($line, ']: ')) {
93
            return $this->formatRequestLine($line);
94
        }
95
        if (str_ends_with(trim($line), 'Accepted') || str_ends_with(trim($line), 'Closing')) {
96
            return $this->verbose ? $this->formatRequestStatusLine($line) : null;
97
        }
98
        if (str_contains($line, '[dashboard@')) {
99
            $message = trim(Str::before($line, '[dashboard@'));
100
            $context = trim(trim(Str::after($line, $message)), '[]');
101
            $success = str_contains($message, 'Created') || str_contains($message, 'Updated');
102
103
            return $this->formatLine($message, Carbon::now(), $success ? 'green-500' : 'blue-500', $context);
104
        }
105
106
        return $this->formatLine($line, Carbon::now());
107
    }
108
109
    protected function formatServerStartedLine(string $line): string
110
    {
111
        return $this->formatLine(sprintf('PHP %s Development Server started. <span class="text-yellow-500">Press Ctrl+C to stop.</span>', PHP_VERSION), $this->parseDate($line), 'green-500');
112
    }
113
114
    protected function formatRequestLine(string $line): string
115
    {
116
        $dateString = Str::betweenFirst($line, '[', ']');
117
        $message = substr($line, strlen($dateString) + 3);
118
119
        $statusCode = Str::between($message, ' [', ']:');
120
        if ($statusCode >= 400) {
121
            $message = str_replace($statusCode, sprintf('<span class="text-red-500">%s</span>', $statusCode), $message);
122
            $iconColor = 'yellow-500';
123
        }
124
125
        return $this->formatLine($message, $this->parseDate($line), $iconColor ?? 'blue-500');
126
    }
127
128
    protected function formatRequestStatusLine(string $line): string
129
    {
130
        $address = trim(Str::between($line, ']', ' '));
131
        $status = str_contains($line, 'Accepted') ? 'Accepted' : 'Closing';
132
133
        return $this->formatLine(sprintf('%s %s', $address, $status), $this->parseDate($line));
134
    }
135
136
    protected static function formatLine(string $message, Carbon $date, string $iconColor = 'blue-500', string $context = ''): string
137
    {
138
        if ($context) {
139
            $context = "$context ";
140
        }
141
142
        return sprintf(<<<'HTML'
143
            <div class="flex w-full justify-between">
144
                <span>
145
                    <span class="text-%s">i</span>
146
                    %s
147
                </span>
148
                <span class="text-gray">%s%s</span>
149
            </div>
150
            HTML,
151
            $iconColor, $message, $context, $date->format('Y-m-d H:i:s')
152
        );
153
    }
154
155
    protected function parseDate(string $line): Carbon
156
    {
157
        return Carbon::parse(Str::betweenFirst($line, '[', ']'));
158
    }
159
}
160