Update code to reach PHPStan max level

This commit is contained in:
Andrea Marco Sartori 2022-12-29 22:07:08 +10:00
parent 1a5accca0f
commit 4df6056671
32 changed files with 113 additions and 127 deletions

View File

@ -9,17 +9,15 @@ namespace Cerbero\JsonParser\Concerns;
trait DetectsEndpoints
{
/**
* Determine whether the given string points to an endpoint
* Determine whether the given value points to an endpoint
*
* @param string $string
* @param string $value
* @return bool
*/
public function isEndpoint(string $string): bool
public function isEndpoint(string $value): bool
{
if (($url = parse_url($string)) === false) {
return false;
}
return isset($url['host']) && in_array($url['scheme'] ?? null, ['http', 'https']);
return is_array($url = parse_url($value))
&& in_array($url['scheme'] ?? null, ['http', 'https'])
&& isset($url['host']);
}
}

View File

@ -12,7 +12,7 @@ use Closure;
* The configuration.
*
*/
class Config
final class Config
{
/**
* The JSON decoder.
@ -31,7 +31,7 @@ class Config
/**
* The number of bytes to read in each chunk.
*
* @var int
* @var int<1, max>
*/
public int $bytes = 1024 * 8;

View File

@ -8,14 +8,14 @@ use Cerbero\JsonParser\Config;
* The configurable decoder.
*
*/
class CustomDecoder
final class ConfigurableDecoder
{
/**
* Instantiate the class.
*
* @param Config $config
*/
public function __construct(protected Config $config)
public function __construct(private Config $config)
{
}

View File

@ -8,14 +8,14 @@ use JsonException;
* The decoded value.
*
*/
class DecodedValue
final class DecodedValue
{
/**
* Instantiate the class.
*
* @param mixed $value
*/
protected function __construct(
private function __construct(
public bool $succeeded,
public mixed $value = null,
public ?string $error = null,

View File

@ -6,7 +6,7 @@ namespace Cerbero\JsonParser\Exceptions;
* The exception thrown when a pointer-related error occurs.
*
*/
class PointerException extends JsonParserException
final class PointerException extends JsonParserException
{
/**
* Retrieve the exception when the given pointer is invalid

View File

@ -6,7 +6,7 @@ namespace Cerbero\JsonParser\Exceptions;
* The exception thrown when a source-related error occurs.
*
*/
class SourceException extends JsonParserException
final class SourceException extends JsonParserException
{
/**
* Retrieve the exception when a JSON source is not supported

View File

@ -13,22 +13,23 @@ use Traversable;
/**
* The JSON parser entry-point.
*
* @implements IteratorAggregate<string|int, mixed>
*/
class JsonParser implements IteratorAggregate
final class JsonParser implements IteratorAggregate
{
/**
* The configuration.
*
* @var Config
*/
protected Config $config;
private Config $config;
/**
* The parser.
*
* @var Parser
*/
protected Parser $parser;
private Parser $parser;
/**
* Instantiate the class.
@ -38,7 +39,7 @@ class JsonParser implements IteratorAggregate
public function __construct(mixed $source)
{
$this->config = new Config();
$this->parser = Parser::for(AnySource::from($source, $this->config));
$this->parser = Parser::for(new AnySource($source, $this->config));
}
/**
@ -91,7 +92,7 @@ class JsonParser implements IteratorAggregate
/**
* The number of bytes to read in each chunk
*
* @param int $bytes
* @param int<1, max> $bytes
* @return static
*/
public function bytes(int $bytes): static

View File

@ -13,43 +13,44 @@ use Traversable;
/**
* The JSON lexer.
*
* @implements IteratorAggregate<int, Token>
*/
class Lexer implements IteratorAggregate
final class Lexer implements IteratorAggregate
{
/**
* The tokenizer.
*
* @var Tokenizer
*/
protected Tokenizer $tokenizer;
private Tokenizer $tokenizer;
/**
* The buffer to yield.
*
* @var string
*/
protected string $buffer = '';
private string $buffer = '';
/**
* Whether the current character is escaped.
*
* @var bool
*/
protected bool $isEscaping = false;
private bool $isEscaping = false;
/**
* Whether the current character belongs to a string.
*
* @var bool
*/
protected bool $inString = false;
private bool $inString = false;
/**
* Instantiate the class.
*
* @param Source $source
*/
public function __construct(protected Source $source)
public function __construct(private Source $source)
{
$this->tokenizer = new Tokenizer();
}
@ -78,7 +79,7 @@ class Lexer implements IteratorAggregate
* @param string $character
* @return bool
*/
protected function inString(string $character): bool
private function inString(string $character): bool
{
return ($character == '"' && $this->inString && $this->isEscaping)
|| ($character != '"' && $this->inString)
@ -91,7 +92,7 @@ class Lexer implements IteratorAggregate
* @param string $character
* @return Generator<int, Token>
*/
protected function yieldOrBufferCharacter(string $character): Generator
private function yieldOrBufferCharacter(string $character): Generator
{
if ($this->inString || !isset(Tokens::BOUNDARIES[$character])) {
$this->buffer .= $character;

View File

@ -2,7 +2,7 @@
namespace Cerbero\JsonParser;
use Cerbero\JsonParser\Decoders\CustomDecoder;
use Cerbero\JsonParser\Decoders\ConfigurableDecoder;
use Cerbero\JsonParser\Sources\Source;
use IteratorAggregate;
use Traversable;
@ -10,22 +10,23 @@ use Traversable;
/**
* The JSON parser.
*
* @implements IteratorAggregate<string|int, mixed>
*/
class Parser implements IteratorAggregate
final class Parser implements IteratorAggregate
{
/**
* The JSON parsing state.
*
* @var State
*/
protected State $state;
private State $state;
/**
* The decoder handling potential errors.
*
* @var CustomDecoder
* @var ConfigurableDecoder
*/
protected CustomDecoder $decoder;
private ConfigurableDecoder $decoder;
/**
* Instantiate the class.
@ -33,10 +34,10 @@ class Parser implements IteratorAggregate
* @param Lexer $lexer
* @param Config $config
*/
public function __construct(protected Lexer $lexer, protected Config $config)
public function __construct(private Lexer $lexer, private Config $config)
{
$this->state = new State();
$this->decoder = new CustomDecoder($config);
$this->decoder = new ConfigurableDecoder($config);
}
/**

View File

@ -10,21 +10,21 @@ use Stringable;
* The JSON pointer.
*
*/
class Pointer implements Stringable
final class Pointer implements Stringable
{
/**
* The reference tokens.
*
* @var string[]
*/
protected array $referenceTokens;
private array $referenceTokens;
/**
* The pointer depth.
*
* @var int
*/
protected int $depth;
private int $depth;
/**
* Whether the pointer was found.
@ -38,7 +38,7 @@ class Pointer implements Stringable
*
* @param string $pointer
*/
public function __construct(protected string $pointer)
public function __construct(private string $pointer)
{
$this->referenceTokens = $this->toReferenceTokens();
$this->depth = count($this->referenceTokens);
@ -49,7 +49,7 @@ class Pointer implements Stringable
*
* @return string[]
*/
protected function toReferenceTokens(): array
private function toReferenceTokens(): array
{
if (preg_match('#^(?:/(?:(?:[^/~])|(?:~[01]))*)*$#', $this->pointer) === 0) {
throw PointerException::invalid($this->pointer);
@ -85,20 +85,15 @@ class Pointer implements Stringable
* Determine whether the reference token at the given depth matches the provided key
*
* @param int $depth
* @param mixed $key
* @param string|int $key
* @return bool
*/
public function depthMatchesKey(int $depth, mixed $key): bool
public function depthMatchesKey(int $depth, string|int $key): bool
{
if (!isset($this->referenceTokens[$depth])) {
return false;
}
$referenceToken = $this->referenceTokens[$depth] ?? null;
if ($this->referenceTokens[$depth] === (string) $key) {
return true;
}
return is_int($key) && $this->referenceTokens[$depth] === '-';
return $referenceToken === (string) $key
|| (is_int($key) && $referenceToken === '-');
}
/**
@ -124,7 +119,7 @@ class Pointer implements Stringable
return true;
}
return (($firstNest = array_search('-', $this->referenceTokens)) !== false)
return is_int($firstNest = array_search('-', $this->referenceTokens))
&& array_slice($this->referenceTokens, 0, $firstNest) === array_slice($tree->original(), 0, $firstNest);
}

View File

@ -8,21 +8,21 @@ use Cerbero\JsonParser\Tree;
* The JSON pointers collection.
*
*/
class Pointers
final class Pointers
{
/**
* The JSON pointers collection.
*
* @var Pointer[]
*/
protected array $pointers;
private array $pointers;
/**
* The list of pointers that were found within the JSON.
*
* @var array
* @var array<string, bool>
*/
protected array $found = [];
private array $found = [];
/**
* Instantiate the class.

View File

@ -23,18 +23,18 @@ class AnySource extends Source
Filename::class,
IterableSource::class,
Json::class,
JsonResource::class,
LaravelClientResponse::class,
Psr7Message::class,
Psr7Stream::class,
Resource::class,
];
/**
* The matching source.
*
* @var Source
* @var Source|null
*/
protected Source $matchingSource;
protected ?Source $matchingSource;
/**
* Retrieve the JSON fragments
@ -61,7 +61,7 @@ class AnySource extends Source
protected function sources(): Generator
{
foreach ($this->supportedSources as $source) {
yield $source::from($this->source, $this->config);
yield new $source($this->source, $this->config);
}
}

View File

@ -7,6 +7,7 @@ use Traversable;
/**
* The custom source.
*
* @property-read Source $source
*/
class CustomSource extends Source
{

View File

@ -11,6 +11,7 @@ use Traversable;
/**
* The endpoint source.
*
* @property-read string $source
*/
class Endpoint extends Source
{
@ -19,9 +20,9 @@ class Endpoint extends Source
/**
* The endpoint response.
*
* @var ResponseInterface
* @var ResponseInterface|null
*/
protected ResponseInterface $response;
protected ?ResponseInterface $response;
/**
* Retrieve the JSON fragments
@ -41,7 +42,7 @@ class Endpoint extends Source
],
]);
return Psr7Message::from($this->response, $this->config);
return new Psr7Message($this->response, $this->config);
}
/**

View File

@ -7,6 +7,7 @@ use Traversable;
/**
* The filename source.
*
* @property-read string $source
*/
class Filename extends Source
{
@ -20,9 +21,9 @@ class Filename extends Source
$handle = fopen($this->source, 'rb');
try {
yield from Resource::from($handle, $this->config);
yield from new JsonResource($handle, $this->config);
} finally {
fclose($handle);
$handle && fclose($handle);
}
}

View File

@ -7,6 +7,7 @@ use Traversable;
/**
* The iterable source.
*
* @property-read iterable $source
*/
class IterableSource extends Source
{
@ -37,6 +38,6 @@ class IterableSource extends Source
*/
protected function calculateSize(): ?int
{
return iterator_count(clone $this->source);
return is_array($this->source) ? count($this->source) : iterator_count(clone $this->source);
}
}

View File

@ -8,6 +8,7 @@ use Traversable;
/**
* The JSON source.
*
* @property-read string $source
*/
class Json extends Source
{

View File

@ -7,8 +7,9 @@ use Traversable;
/**
* The resource source.
*
* @property-read resource $source
*/
class Resource extends Source
class JsonResource extends Source
{
/**
* Retrieve the JSON fragments
@ -18,7 +19,9 @@ class Resource extends Source
public function getIterator(): Traversable
{
while (!feof($this->source)) {
yield fread($this->source, $this->config->bytes);
if (is_string($chunk = fread($this->source, $this->config->bytes))) {
yield $chunk;
}
}
}
@ -29,7 +32,7 @@ class Resource extends Source
*/
public function matches(): bool
{
return is_resource($this->source) || get_resource_type($this->source) == 'stream';
return is_resource($this->source);
}
/**

View File

@ -8,6 +8,7 @@ use Traversable;
/**
* The Laravel client response source.
*
* @property-read Response $source
*/
class LaravelClientResponse extends Source
{
@ -18,7 +19,7 @@ class LaravelClientResponse extends Source
*/
public function getIterator(): Traversable
{
return Psr7Message::from($this->source->toPsrResponse(), $this->config);
return new Psr7Message($this->source->toPsrResponse(), $this->config);
}
/**

View File

@ -8,6 +8,7 @@ use Traversable;
/**
* The PSR-7 message source.
*
* @property-read MessageInterface $source
*/
class Psr7Message extends Source
{
@ -18,7 +19,7 @@ class Psr7Message extends Source
*/
public function getIterator(): Traversable
{
return Psr7Stream::from($this->source->getBody(), $this->config);
return new Psr7Stream($this->source->getBody(), $this->config);
}
/**

View File

@ -8,6 +8,7 @@ use Traversable;
/**
* The PSR-7 stream source.
*
* @property-read StreamInterface $source
*/
class Psr7Stream extends Source
{
@ -26,7 +27,7 @@ class Psr7Stream extends Source
StreamWrapper::NAME => ['stream' => $this->source],
]));
return Resource::from($stream, $this->config);
return new JsonResource($stream, $this->config);
}
/**

View File

@ -9,6 +9,7 @@ use Traversable;
/**
* The JSON source.
*
* @implements IteratorAggregate<int, string>
*/
abstract class Source implements IteratorAggregate
{
@ -17,7 +18,7 @@ abstract class Source implements IteratorAggregate
*
* @var int|null
*/
protected int $size;
protected ?int $size;
/**
* Retrieve the JSON fragments
@ -46,22 +47,10 @@ abstract class Source implements IteratorAggregate
* @param mixed $source
* @param Config $config
*/
protected function __construct(protected mixed $source, protected Config $config)
final public function __construct(protected mixed $source, protected Config $config)
{
}
/**
* Instantiate the class statically
*
* @param mixed $source
* @param Config $config
* @return static
*/
public static function from(mixed $source, Config $config): static
{
return new static($source, $config);
}
/**
* Retrieve the underlying configuration
*

View File

@ -9,7 +9,7 @@ use Psr\Http\Message\StreamInterface;
*
* @phpcs:disable PSR1.Methods.CamelCapsMethodName.NotCamelCaps
*/
class StreamWrapper
final class StreamWrapper
{
/**
* The name of the stream wrapper.
@ -23,14 +23,14 @@ class StreamWrapper
*
* @var resource
*/
public $context;
public mixed $context;
/**
* The PSR-7 stream.
*
* @var StreamInterface
*/
protected $stream;
private $stream;
/**
* Open the stream

View File

@ -10,35 +10,35 @@ use Cerbero\JsonParser\Tokens\Token;
* The JSON parsing state.
*
*/
class State
final class State
{
/**
* The JSON tree.
*
* @var Tree
*/
protected Tree $tree;
private Tree $tree;
/**
* The JSON pointers.
*
* @var Pointers
*/
protected Pointers $pointers;
private Pointers $pointers;
/**
* The JSON pointer matching the tree.
*
* @var Pointer
*/
protected Pointer $pointer;
private Pointer $pointer;
/**
* The JSON buffer.
*
* @var string
*/
protected string $buffer = '';
private string $buffer = '';
/**
* Whether an object key is expected.
@ -81,9 +81,9 @@ class State
/**
* Retrieve the current key of the JSON tree
*
* @return string
* @return string|int
*/
public function key(): string
public function key(): string|int
{
return $this->tree->currentKey();
}
@ -160,7 +160,7 @@ class State
* @param Token $token
* @return void
*/
protected function bufferToken(Token $token): void
private function bufferToken(Token $token): void
{
$shouldBuffer = $this->tree->depth() >= 0
&& $this->pointer->matchesTree($this->tree)

View File

@ -8,7 +8,7 @@ use Cerbero\JsonParser\State;
* The comma token.
*
*/
class Comma extends Token
final class Comma extends Token
{
/**
* Retrieve the token type
@ -28,8 +28,6 @@ class Comma extends Token
*/
public function mutateState(State $state): void
{
if ($state->inObject()) {
$state->expectsKey = true;
}
$state->expectsKey = $state->inObject();
}
}

View File

@ -8,7 +8,7 @@ use Cerbero\JsonParser\State;
* The token that begins compound data (JSON arrays or objects).
*
*/
class CompoundBegin extends Token
final class CompoundBegin extends Token
{
/**
* Retrieve the token type
@ -30,8 +30,6 @@ class CompoundBegin extends Token
{
$state->tree()->deepen();
if ($this->value == '{') {
$state->expectsKey = true;
}
$state->expectsKey = $this->value == '{';
}
}

View File

@ -8,7 +8,7 @@ use Cerbero\JsonParser\State;
* The token that ends compound data (JSON arrays or objects).
*
*/
class CompoundEnd extends Token
final class CompoundEnd extends Token
{
/**
* Retrieve the token type
@ -29,10 +29,6 @@ class CompoundEnd extends Token
public function mutateState(State $state): void
{
$state->tree()->emerge();
if ($this->value == '}') {
$state->expectsKey = false;
}
}
/**

View File

@ -6,7 +6,7 @@ namespace Cerbero\JsonParser\Tokens;
* The constant token, includes colons for convenience.
*
*/
class Constant extends Token
final class Constant extends Token
{
/**
* Retrieve the token type

View File

@ -8,14 +8,14 @@ use Cerbero\JsonParser\State;
* The scalar string token.
*
*/
class ScalarString extends Token
final class ScalarString extends Token
{
/**
* Whether this token is an object key.
*
* @var bool
*/
protected bool $isKey = false;
private bool $isKey = false;
/**
* Retrieve the token type

View File

@ -6,14 +6,14 @@ namespace Cerbero\JsonParser\Tokens;
* The tokenizer.
*
*/
class Tokenizer
final class Tokenizer
{
/**
* The map of token instances by type.
*
* @var array<int, Token>
*/
protected static array $tokensMap;
private static array $tokensMap;
/**
* Instantiate the class.
@ -29,7 +29,7 @@ class Tokenizer
*
* @return array<int, Token>
*/
protected function hydrateTokensMap(): array
private function hydrateTokensMap(): array
{
$map = $instances = [];

View File

@ -6,7 +6,7 @@ namespace Cerbero\JsonParser\Tokens;
* The tokens related information.
*
*/
class Tokens
final class Tokens
{
public const SCALAR_CONST = 1 << 0;
public const SCALAR_STRING = 1 << 1;
@ -35,7 +35,7 @@ class Tokens
/**
* The token types.
*
* @var array
* @var array<string|int, int>
*/
public const TYPES = [
'n' => self::SCALAR_CONST,
@ -64,7 +64,7 @@ class Tokens
/**
* The token boundaries.
*
* @var array
* @var array<string, bool>
*/
public const BOUNDARIES = [
"\xEF" => true,
@ -85,7 +85,7 @@ class Tokens
/**
* The structural boundaries.
*
* @var array
* @var array<string, bool>
*/
public const DELIMITERS = [
'{' => true,

View File

@ -2,34 +2,32 @@
namespace Cerbero\JsonParser;
use Cerbero\JsonParser\Pointers\Pointer;
/**
* The JSON tree.
*
*/
class Tree
final class Tree
{
/**
* The original JSON tree.
*
* @var array<int, string|int>
*/
protected array $original = [];
private array $original = [];
/**
* The wildcarded JSON tree.
*
* @var array<int, string|int>
*/
protected array $wildcarded = [];
private array $wildcarded = [];
/**
* The JSON tree depth.
*
* @var int
*/
protected int $depth = -1;
private int $depth = -1;
/**
* Retrieve the original JSON tree
@ -102,7 +100,7 @@ class Tree
*
* @return void
*/
protected function trim(): void
private function trim(): void
{
array_splice($this->original, $this->depth + 1);
array_splice($this->wildcarded, $this->depth + 1);