Skip to content

Commit

Permalink
feat: add method to get type parser by type name
Browse files Browse the repository at this point in the history
  • Loading branch information
ramsey committed May 2, 2023
1 parent f627f02 commit c3ae959
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 10 deletions.
14 changes: 6 additions & 8 deletions src/Parser/LexiconDocParser.php
Expand Up @@ -17,9 +17,9 @@
use SocialWeb\Atproto\Lexicon\Types\LexRef;
use SocialWeb\Atproto\Lexicon\Types\LexString;
use SocialWeb\Atproto\Lexicon\Types\LexToken;
use SocialWeb\Atproto\Lexicon\Types\LexType;
use SocialWeb\Atproto\Lexicon\Types\LexUnion;
use SocialWeb\Atproto\Lexicon\Types\LexUnknown;
use SocialWeb\Atproto\Lexicon\Types\LexUserType;
use SocialWeb\Atproto\Lexicon\Types\LexVideo;
use SocialWeb\Atproto\Lexicon\Types\LexXrpcBody;
use SocialWeb\Atproto\Lexicon\Types\LexXrpcError;
Expand Down Expand Up @@ -111,16 +111,14 @@ public function parse(object | string $data): LexiconDoc
return $doc;
}

private function parseDef(object $def): LexArray | LexPrimitive | LexRef | LexUnion | LexUserType
private function parseDef(object $def): LexType
{
$type = $def->type ?? null;
assert($type === null || is_string($type));
$type = $def->type ?? '';
assert(is_string($type));

return match ($type) {
'array' => $this->parseArray($def),
'audio' => $this->getParserFactory()->getParser(LexAudioParser::class)->parse($def),
'blob' => $this->parseBlob($def),
'boolean' => $this->getParserFactory()->getParser(LexBooleanParser::class)->parse($def),
'image' => $this->parseImage($def),
'integer' => $this->parseInteger($def),
'number' => $this->parseNumber($def),
Expand All @@ -134,7 +132,7 @@ private function parseDef(object $def): LexArray | LexPrimitive | LexRef | LexUn
'union' => $this->parseUnion($def),
'unknown' => $this->parseUnknown($def),
'video' => $this->parseVideo($def),
default => throw new UnableToParse("Encountered unknown type \"$type\""),
default => $this->getParserFactory()->getParserByTypeName($type)->parse($def),
};
}

Expand Down Expand Up @@ -341,7 +339,7 @@ private function parseRecord(object $def): LexRecord
return new LexRecord($this->parseObject($record), $key, $description);
}

private function parseRef(object $def): LexArray | LexPrimitive | LexRef | LexUnion | LexUserType
private function parseRef(object $def): LexType
{
$ref = $def->ref ?? null;

Expand Down
34 changes: 34 additions & 0 deletions src/Parser/ParserFactory.php
Expand Up @@ -9,6 +9,29 @@

class ParserFactory
{
/**
* @var array<string, class-string<Parser> | null>
*/
private array $typeParserMap = [
'array' => null,
'audio' => LexAudioParser::class,
'blob' => null,
'boolean' => LexBooleanParser::class,
'image' => null,
'integer' => null,
'number' => null,
'object' => null,
'procedure' => null,
'query' => null,
'record' => null,
'ref' => null,
'string' => null,
'token' => null,
'union' => null,
'unknown' => null,
'video' => null,
];

/**
* @param array<class-string<Parser>, Parser> $parsers
*/
Expand Down Expand Up @@ -45,4 +68,15 @@ public function getParser(string $name): Parser
/** @var T */
return $parser;
}

public function getParserByTypeName(string $typeName): Parser
{
$className = $this->typeParserMap[$typeName] ?? null;

if ($className === null) {
throw new ParserNotFound("Unable to find parser for \"$typeName\"");
}

return $this->getParser($className);
}
}
2 changes: 1 addition & 1 deletion src/Types/LexUnion.php
Expand Up @@ -9,7 +9,7 @@ final class LexUnion implements LexType
public readonly LexPrimitiveType $type;

/**
* @param string[] | array<LexArray | LexPrimitive | LexRef | LexUnion | LexUserType> $refs
* @param string[] | array<LexType> $refs
*/
public function __construct(
public readonly array $refs,
Expand Down
2 changes: 1 addition & 1 deletion src/Types/LexiconDoc.php
Expand Up @@ -10,7 +10,7 @@ final class LexiconDoc implements LexType

/**
* @param string $id An NSID
* @param array<string, LexArray | LexPrimitive | LexRef | LexUnion | LexUserType> $defs
* @param array<string, LexType> $defs
*/
public function __construct(
public readonly string $id,
Expand Down
43 changes: 43 additions & 0 deletions tests/Parser/ParserFactoryTest.php
Expand Up @@ -5,6 +5,8 @@
namespace SocialWeb\Test\Atproto\Lexicon\Parser;

use PHPUnit\Framework\Attributes\TestWith;
use SocialWeb\Atproto\Lexicon\Parser\LexAudioParser;
use SocialWeb\Atproto\Lexicon\Parser\LexBooleanParser;
use SocialWeb\Atproto\Lexicon\Parser\Parser;
use SocialWeb\Atproto\Lexicon\Parser\ParserFactory;
use SocialWeb\Atproto\Lexicon\Parser\ParserNotFound;
Expand Down Expand Up @@ -52,4 +54,45 @@ public function testGetParserConstructsAndStoresParser(): void
$this->assertSame(0, $parser1->parseCalled);
$this->assertSame($parser1, $parser2);
}

/**
* @param class-string<Parser> $expectedParserClass
*/
#[TestWith(['audio', LexAudioParser::class])]
#[TestWith(['boolean', LexBooleanParser::class])]
public function testGetParserByTypeName(string $typeName, string $expectedParserClass): void
{
$schemaRepository = new SchemaRepository(__DIR__ . '/../schemas');
$parserRepository = new ParserFactory($schemaRepository);
$parser = $parserRepository->getParserByTypeName($typeName);

$this->assertInstanceOf($expectedParserClass, $parser);
}

#[TestWith(['foobar'])]
#[TestWith(['array'])]
#[TestWith(['blob'])]
#[TestWith(['image'])]
#[TestWith(['integer'])]
#[TestWith(['number'])]
#[TestWith(['object'])]
#[TestWith(['procedure'])]
#[TestWith(['query'])]
#[TestWith(['record'])]
#[TestWith(['ref'])]
#[TestWith(['string'])]
#[TestWith(['token'])]
#[TestWith(['union'])]
#[TestWith(['unknown'])]
#[TestWith(['video'])]
public function testGetParserByTypeNameThrowsForUnknownTypeName(string $typeName): void
{
$schemaRepository = new SchemaRepository(__DIR__ . '/../schemas');
$parserRepository = new ParserFactory($schemaRepository);

$this->expectException(ParserNotFound::class);
$this->expectExceptionMessage("Unable to find parser for \"$typeName\"");

$parserRepository->getParserByTypeName($typeName);
}
}

0 comments on commit c3ae959

Please sign in to comment.