Skip to content

Commit

Permalink
Merge pull request #57: Fix psalm issues
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk committed May 2, 2024
2 parents e414dfc + 743d5d6 commit f80e8d8
Show file tree
Hide file tree
Showing 24 changed files with 255 additions and 401 deletions.
411 changes: 71 additions & 340 deletions psalm-baseline.xml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions src/Proto/Frame/Smtp.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
/**
* @internal
* @psalm-internal Buggregator
* @psalm-import-type TArrayData from Message\Smtp
*/
final class Smtp extends Frame implements FilesCarrier
{
Expand All @@ -34,6 +35,7 @@ public function __toString(): string

public static function fromString(string $payload, DateTimeImmutable $time): static
{
/** @var TArrayData $payload */
$payload = \json_decode($payload, true, \JSON_THROW_ON_ERROR);
$message = Message\Smtp::fromArray($payload);

Expand Down
2 changes: 1 addition & 1 deletion src/Sender/Console/Renderer/SentryEnvelope.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function render(OutputInterface $output, Frame $frame): void
++$i;
try {
$type = $item->headers['type'] ?? null;
Common::renderHeader2($output, "Item $i", green: $type);
Common::renderHeader2($output, "Item $i", green: (string)$type);

Header::renderMessageHeader($output, $item->payload);
$this->renderItem($output, $item);
Expand Down
4 changes: 2 additions & 2 deletions src/Sender/Console/Renderer/Smtp.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ public function render(OutputInterface $output, Frame $frame): void
foreach ($message->getAttachments() as $attach) {
Files::renderFile(
$output,
$attach->getClientFilename(),
$attach->getClientFilename() ?? '',
$attach->getSize(),
$attach->getClientMediaType(),
$attach->getClientMediaType() ?? '',
);
}
$output->writeln('');
Expand Down
1 change: 1 addition & 0 deletions src/Sender/Console/Renderer/TemplateRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public function __construct(

public function render(string $template, array $data = []): void
{
/** @psalm-suppress InternalMethod */
$this->renderer->render(
$this->templateEngine->render($template, $data),
0
Expand Down
6 changes: 3 additions & 3 deletions src/Sender/Console/Renderer/VarDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public function __construct(
}

/**
* @psalm-suppress RiskyTruthyFalsyComparison
* @psalm-suppress RiskyTruthyFalsyComparison, MixedArrayAccess, MixedArgument
*/
public function describe(OutputInterface $output, Data $data, array $context, int $clientId): void
{
Expand Down Expand Up @@ -94,7 +94,7 @@ public function describe(OutputInterface $output, Data $data, array $context, in
empty($request['method'] ?? '') or $meta['Method'] = $request['method'];
empty($request['uri'] ?? '') or $meta['URI'] = $request['uri'];
if ($controller = $request['controller']) {
$meta['Controller'] = rtrim($this->dumper->dump($controller, true), "\n");
$meta['Controller'] = \rtrim((string) $this->dumper->dump($controller, true), "\n");
}
} elseif (isset($context['cli'])) {
$meta['Command'] = $context['cli']['command_line'];
Expand All @@ -107,7 +107,7 @@ public function describe(OutputInterface $output, Data $data, array $context, in
Common::renderMetadata($output, $meta);
$output->writeln('');

$output->write($this->dumper->dump($data, true), true, OutputInterface::OUTPUT_RAW);
$output->write((string) $this->dumper->dump($data, true), true, OutputInterface::OUTPUT_RAW);
}
};
}
Expand Down
10 changes: 8 additions & 2 deletions src/Sender/Console/Support/Common.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ public static function renderHeader2(OutputInterface $output, string $title, str
{
$parts = ["<fg=white;options=bold># $title </>"];
foreach ($sub as $color => $value) {
if ($value === '') {
continue;
}

$color = \is_string($color) ? $color : 'gray';
$parts[] = \sprintf('<fg=%s> %s </>', $color, $value);
}
Expand Down Expand Up @@ -57,9 +61,11 @@ public static function renderHighlightedLine(OutputInterface $output, string $li
*/
public static function renderMetadata(OutputInterface $output, array $data): void
{
$maxHeaderLength = \max(\array_map('strlen', \array_keys($data)));
$maxHeaderLength = \max(0, ...\array_map(
static fn(string|int $key): int => \strlen((string) $key),
\array_keys($data)),
);

/** @var mixed $value */
foreach ($data as $head => $value) {
// Align headers to the right
self::renderHeader(
Expand Down
8 changes: 6 additions & 2 deletions src/Sender/Console/Support/Files.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
final class Files
{
/**
* @param non-negative-int|null $size
*
* Render file info. Example:
* ┌───┐ logo.ico
* │ico│ 20.06 KiB
Expand All @@ -33,8 +35,10 @@ public static function renderFile(
string ...$additional
): void {
// File extension
$ex = \substr($fileName, \strrpos($fileName, '.') + 1);
$ex = \strlen($ex) > 3 ? ' ' : \str_pad($ex, 3, ' ', \STR_PAD_BOTH);
$dotPos = \strrpos($fileName, '.');
$ex = $dotPos === false || \strlen($fileName) - $dotPos > 4
? ' '
: \str_pad(\substr($fileName, $dotPos + 1), 3, ' ', \STR_PAD_BOTH);

// File size
$sizeStr = self::normalizeSize($size) ?? 'unknown size';
Expand Down
2 changes: 1 addition & 1 deletion src/Sender/Console/Support/Tables.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public static function renderKeyValueTable(OutputInterface $output, string $titl
return;
}

$keyLength = \max(\array_map(static fn($key) => \strlen($key), \array_keys($data)));
$keyLength = \max(\array_map(static fn($key) => \strlen((string) $key), \array_keys($data)));
$valueLength = \max(1, (new Terminal())->getWidth() - 7 - $keyLength);

$table->setRows([...(static function (array $data) use ($valueLength): iterable {
Expand Down
2 changes: 2 additions & 0 deletions src/Sender/ConsoleSender.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ final class ConsoleSender implements Sender
{
public static function create(OutputInterface $output): self
{
/** @psalm-suppress InternalMethod, InternalClass */
Termwind::renderUsing($output);

/** @psalm-suppress InternalClass */
$templateRenderer = new TemplateRenderer(
new HtmlRenderer(),
new TemplateEngine(Info::TRAP_ROOT . '/resources/templates')
Expand Down
11 changes: 7 additions & 4 deletions src/Socket/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ final class Client implements Destroyable
private \Closure $onPayload;
private \Closure $onClose;

/**
* @param positive-int $payloadSize
*/
private function __construct(
private readonly \Socket $socket,
private readonly int $payloadSize,
Expand Down Expand Up @@ -112,21 +115,21 @@ protected function onInit(): void
}

/**
* @param callable(string): void $callable Non-static callable.
* @param callable(string): void $callable If non-static callable, it will be bound to the current instance.
* @psalm-assert callable(string): void $callable
*/
public function setOnPayload(callable $callable): void
{
$this->onPayload = \Closure::bind($callable(...), $this);
$this->onPayload = \Closure::bind($callable(...), $this) ?? $callable(...);
}

/**
* @param callable(): void $callable Non-static callable.
* @param callable(): void $callable If non-static callable, it will be bound to the current instance.
* @psalm-assert callable(): void $callable
*/
public function setOnClose(callable $callable): void
{
$this->onClose = \Closure::bind($callable(...), $this);
$this->onClose = \Closure::bind($callable(...), $this) ?? $callable(...);
}

public function send(string $payload): void
Expand Down
10 changes: 4 additions & 6 deletions src/Socket/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
*/
final class Server implements Processable, Cancellable, Destroyable
{
/** @var false|resource|Socket */
private $socket;
private Socket $socket;

/** @var array<int, Client> */
private array $clients = [];
Expand All @@ -41,13 +40,11 @@ private function __construct(
private readonly ?Closure $clientInflector,
private readonly Logger $logger,
) {
$this->socket = @\socket_create_listen($port);
$this->socket = @\socket_create_listen($port) ?: throw new \RuntimeException('Socket create failed.');

/** @link https://github.com/buggregator/trap/pull/14 */
// \socket_set_option($this->socket, \SOL_SOCKET, \SO_LINGER, ['l_linger' => 0, 'l_onoff' => 1]);

if ($this->socket === false) {
throw new \RuntimeException('Socket create failed.');
}
\socket_set_nonblock($this->socket);

$logger->status('Application', 'Server started on 127.0.0.1:%s', $port);
Expand Down Expand Up @@ -92,6 +89,7 @@ public static function init(

public function process(): void
{
// /** @psalm-suppress PossiblyInvalidArgument */
while (!$this->cancelled and false !== ($socket = \socket_accept($this->socket))) {
$client = null;
try {
Expand Down
2 changes: 1 addition & 1 deletion src/Support/StreamHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static function strpos(StreamInterface $stream, string $substr): int|fals
*
* @param non-empty-string $boundary
*
* @return int Bytes written
* @return int<0, max> Bytes written
*/
public static function writeStreamUntil(StreamInterface $from, StreamInterface $to, string $boundary): int
{
Expand Down
2 changes: 1 addition & 1 deletion src/Traffic/Dispatcher/Http.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public function __construct(
/** @see RequestHandler::handle() */
'handle',
static function (): never { throw new \LogicException('No handler found for request.'); },
Generator::class,
'never',
);
}

Expand Down
3 changes: 2 additions & 1 deletion src/Traffic/Dispatcher/Smtp.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ public function __construct(
public function dispatch(StreamClient $stream): iterable
{
$stream->sendData($this->createResponse(self::READY, 'mailamie'));

$protocol = [];

$message = null;
Expand All @@ -40,9 +39,11 @@ public function dispatch(StreamClient $stream): iterable
if (\preg_match('/^(?:EHLO|HELO)/', $response)) {
$stream->sendData($this->createResponse(self::OK));
} elseif (\preg_match('/^MAIL FROM:\s*<(.*)>/', $response, $matches)) {
/** @var array{0: non-empty-string, 1: string} $matches */
$protocol['FROM'][] = $matches[1];
$stream->sendData($this->createResponse(self::OK));
} elseif (\preg_match('/^RCPT TO:\s*<(.*)>/', $response, $matches)) {
/** @var array{0: non-empty-string, 1: string} $matches */
$protocol['BCC'][] = $matches[1];
$stream->sendData($this->createResponse(self::OK));
} elseif (\str_starts_with($response, 'QUIT')) {
Expand Down
26 changes: 18 additions & 8 deletions src/Traffic/Message/Headers.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
*/
trait Headers
{
/** @var array Map of all registered headers, as original name => array of values */
/** @var array<non-empty-string, non-empty-list<string>> Map of all registered headers */
private array $headers = [];

/** @var array Map of lowercase header name => original name at registration */
/** @var array<non-empty-string, non-empty-string> Map of lowercase header name => original name at registration */
private array $headerNames = [];

/**
* @return array<non-empty-string, list<string>>
*/
public function getHeaders(): array
{
return $this->headers;
Expand All @@ -26,7 +29,7 @@ public function hasHeader(string $header): bool
}

/**
* @return string[]
* @return list<string>
*/
public function getHeader(string $header): array
{
Expand All @@ -45,9 +48,10 @@ public function getHeaderLine(string $header): string
return \implode(', ', $this->getHeader($header));
}

public function withHeader(string $header, $value): static
public function withHeader(string $header, mixed $value): static
{
$value = $this->validateAndTrimHeader($header, $value);
/** @var non-empty-string $normalized */
$normalized = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');

$new = clone $this;
Expand Down Expand Up @@ -97,7 +101,9 @@ private function setHeaders(array $headers): void
// We must cast it back to a string in order to comply with validation.
$header = (string)$header;
}

$value = $this->validateAndTrimHeader($header, $value);
/** @var non-empty-string $normalized */
$normalized = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
if (isset($this->headerNames[$normalized])) {
$header = $this->headerNames[$normalized];
Expand Down Expand Up @@ -126,8 +132,12 @@ private function setHeaders(array $headers): void
* field-value = *( ( %x21-7E / %x80-FF ) [ 1*( SP / HTAB ) ( %x21-7E / %x80-FF ) ] )
*
* @see https://tools.ietf.org/html/rfc7230#section-3.2.4
*
* @psalm-assert non-empty-string $header
*
* @return non-empty-list<string>
*/
private function validateAndTrimHeader(string $header, $values): array
private function validateAndTrimHeader(string $header, mixed $values): array
{
if (1 !== \preg_match("@^[!#$%&'*+.^_`|~0-9A-Za-z-]+$@D", $header)) {
throw new \InvalidArgumentException('Header name must be an RFC 7230 compatible string');
Expand Down Expand Up @@ -170,17 +180,17 @@ private function validateAndTrimHeader(string $header, $values): array
/**
* List of header values.
*
* @param array<string, list<non-empty-string>> $headers
* @param array<array-key, list<string>> $headers
* @param non-empty-string $header
*
* @return list<non-empty-string>
* @return list<string>
*/
private static function findHeader(array $headers, string $header): array
{
$header = \strtr($header, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
$result = [];
foreach ($headers as $name => $values) {
if (\strtr($name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') === $header) {
if (\strtr((string) $name, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz') === $header) {
$result = [...$result, ...$values];
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/Traffic/Message/Multipart/Field.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

/**
* @psalm-type FieldDataArray = array{
* headers: array<string, non-empty-list<string>>,
* headers: array<array-key, non-empty-list<string>>,
* name?: string,
* value: string
* }
Expand All @@ -15,6 +15,9 @@
*/
final class Field extends Part
{
/**
* @param array<array-key, non-empty-list<string>> $headers
*/
public function __construct(array $headers, ?string $name = null, private string $value = '')
{
parent::__construct($headers, $name);
Expand All @@ -30,6 +33,7 @@ public static function fromArray(array $data): self

/**
* @return FieldDataArray
* @psalm-suppress ImplementedReturnTypeMismatch
*/
public function jsonSerialize(): array
{
Expand Down
Loading

0 comments on commit f80e8d8

Please sign in to comment.