Passed
Push — master ( 5ba04d...132c5f )
by Caen
07:16 queued 03:37
created

ConsoleOutput::formatServerStartedLine()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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