Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix psalm, clear psalm-baseline.yaml #57

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading