-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
1,384 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Riverwaysoft\PhpConverter\OutputGenerator\Go; | ||
|
||
class GoGeneratorOptions | ||
{ | ||
public function __construct() {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Riverwaysoft\PhpConverter\OutputGenerator\Go; | ||
|
||
use Exception; | ||
use Riverwaysoft\PhpConverter\Ast\ConverterResult; | ||
use Riverwaysoft\PhpConverter\Dto\DtoClassProperty; | ||
use Riverwaysoft\PhpConverter\Dto\DtoEnumProperty; | ||
use Riverwaysoft\PhpConverter\Dto\DtoList; | ||
use Riverwaysoft\PhpConverter\Dto\DtoType; | ||
use Riverwaysoft\PhpConverter\Dto\ExpressionType; | ||
use Riverwaysoft\PhpConverter\OutputGenerator\OutputGeneratorInterface; | ||
use Riverwaysoft\PhpConverter\OutputGenerator\PropertyNameGeneratorInterface; | ||
use Riverwaysoft\PhpConverter\OutputWriter\OutputFile; | ||
use Riverwaysoft\PhpConverter\OutputWriter\OutputProcessor\OutputFilesProcessor; | ||
use Riverwaysoft\PhpConverter\OutputWriter\OutputProcessor\PrependAutogeneratedNoticeFileProcessor; | ||
use Riverwaysoft\PhpConverter\OutputWriter\OutputWriterInterface; | ||
use function sprintf; | ||
|
||
class GoOutputGenerator | ||
implements OutputGeneratorInterface | ||
{ | ||
private GoGeneratorOptions $options; | ||
Check failure on line 25 in src/OutputGenerator/Go/GoOutputGenerator.php GitHub Actions / PHP 8.0 Test on ubuntu latest
|
||
|
||
/** @var PropertyNameGeneratorInterface[] */ | ||
private array $propertyNameGenerators; | ||
|
||
/** @param PropertyNameGeneratorInterface[] $propertyNameGenerators */ | ||
public function __construct( | ||
private OutputWriterInterface $outputWriter, | ||
private GoTypeResolver $typeResolver, | ||
private ?OutputFilesProcessor $outputFilesProcessor = null, | ||
array $propertyNameGenerators = [], | ||
?GoGeneratorOptions $options = null, | ||
) { | ||
$this->options = $options ?? new GoGeneratorOptions(); | ||
$this->outputFilesProcessor = $this->outputFilesProcessor ?? new OutputFilesProcessor( | ||
[ | ||
new PrependAutogeneratedNoticeFileProcessor( | ||
text: <<<TEXT | ||
// THE FILE WAS AUTOGENERATED USING PHP-CONVERTER. PLEASE DO NOT EDIT IT! | ||
// THE FILE WAS AUTOGENERATED USING PHP-CONVERTER. PLEASE DO NOT EDIT IT! | ||
// THE FILE WAS AUTOGENERATED USING PHP-CONVERTER. PLEASE DO NOT EDIT IT! | ||
package gen | ||
TEXT | ||
), | ||
] | ||
); | ||
$this->propertyNameGenerators = $propertyNameGenerators ?: [ | ||
new GoPropertyNameGenerator(), | ||
]; | ||
} | ||
|
||
/** @return OutputFile[] */ | ||
public function generate(ConverterResult $converterResult): array | ||
{ | ||
$this->outputWriter->reset(); | ||
|
||
$dtoList = $converterResult->dtoList; | ||
foreach ($dtoList->getList() as $dto) { | ||
$result = $this->convertToGoType($dto, $dtoList); | ||
$this->outputWriter->writeType($result, $dto); | ||
} | ||
|
||
$files = $this->outputWriter->getTypes(); | ||
|
||
return $this->outputFilesProcessor->process($files); | ||
} | ||
|
||
/** @var string[] */ | ||
private array $usedConstantsStore = []; | ||
|
||
private function convertToGoType(DtoType $dto, DtoList $dtoList): string | ||
{ | ||
if ($dto->getExpressionType()->equals(ExpressionType::class())) { | ||
$typeName = $dto->getName(); | ||
$convertedProperties = ''; | ||
|
||
/** @param DtoClassProperty[] $properties */ | ||
$properties = $dto->getProperties(); | ||
foreach ($properties as $property) { | ||
$convertedProperties .= sprintf( | ||
"\n %s %s", | ||
$this | ||
->getPropertyNameGenerator($dto) | ||
->generate($property), | ||
$this->typeResolver->getTypeFromPhp( | ||
$property->getType(), | ||
$dto, | ||
$dtoList | ||
) | ||
); | ||
} | ||
|
||
return sprintf( | ||
"type %s struct {%s\n}", | ||
$typeName, | ||
$convertedProperties | ||
); | ||
} | ||
if ($dto->getExpressionType()->isAnyEnum()) { | ||
$firstEnumProperty = $dto->getProperties()[0] ?? null; | ||
if ($firstEnumProperty === null) { | ||
throw new Exception('Enum must have at least one property'); | ||
} | ||
|
||
$firstEnumPropertyValue = $firstEnumProperty->getValue(); | ||
if (is_int($firstEnumPropertyValue)) { | ||
$type = 'int'; | ||
} elseif (is_string($firstEnumPropertyValue)) { | ||
$type = 'string'; | ||
} else { | ||
$type = 'any'; | ||
} | ||
|
||
return sprintf( | ||
"type %s %s \n\nconst(%s\n)", | ||
$dto->getName(), | ||
$type, | ||
$this->convertEnumToTypeScriptEnumProperties( | ||
$dto->getProperties(), | ||
$dto->getName(), | ||
) | ||
); | ||
} | ||
throw new Exception( | ||
'Unknown expression type '. | ||
$dto->getExpressionType()->jsonSerialize() | ||
); | ||
} | ||
|
||
private function getPropertyNameGenerator( | ||
DtoType $dto | ||
): PropertyNameGeneratorInterface { | ||
if (count($this->propertyNameGenerators) === 1) { | ||
return $this->propertyNameGenerators[0]; | ||
} | ||
|
||
foreach ($this->propertyNameGenerators as $propertyNameGenerator) { | ||
if ($propertyNameGenerator->supports($dto)) { | ||
return $propertyNameGenerator; | ||
} | ||
} | ||
|
||
throw new Exception( | ||
'Property name generator not found for type '.$dto->getName() | ||
); | ||
} | ||
|
||
/** @param DtoEnumProperty[] $properties */ | ||
private function convertEnumToTypeScriptEnumProperties( | ||
array $properties, | ||
string $enumName | ||
): string { | ||
$string = ''; | ||
|
||
foreach ($properties as $property) { | ||
$propertyValue = $property->isNumeric() | ||
? $property->getValue() | ||
: sprintf("\"%s\"", $property->getValue()); | ||
|
||
$constName = $property->getName(); | ||
if (in_array($constName, $this->usedConstantsStore)) { | ||
$constName .= $enumName; | ||
} | ||
|
||
if (array_key_exists($constName, $this->usedConstantsStore)) { | ||
throw new Exception( | ||
'Please rename constant '.$constName | ||
); | ||
} | ||
$this->usedConstantsStore[] = $constName; | ||
|
||
$string .= sprintf( | ||
"\n %s %s = %s", | ||
$constName, | ||
$enumName, | ||
$propertyValue | ||
); | ||
} | ||
|
||
return $string; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Riverwaysoft\PhpConverter\OutputGenerator\Go; | ||
|
||
use Riverwaysoft\PhpConverter\Dto\DtoClassProperty; | ||
use Riverwaysoft\PhpConverter\Dto\DtoType; | ||
use Riverwaysoft\PhpConverter\OutputGenerator\PropertyNameGeneratorInterface; | ||
|
||
class GoPropertyNameGenerator implements PropertyNameGeneratorInterface | ||
{ | ||
public function supports(DtoType $dto): bool | ||
{ | ||
return true; | ||
} | ||
|
||
public function generate(DtoClassProperty $property): string | ||
{ | ||
return ucfirst($property->getName()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Riverwaysoft\PhpConverter\OutputGenerator\Go; | ||
|
||
use Exception; | ||
use Riverwaysoft\PhpConverter\Dto\DtoList; | ||
use Riverwaysoft\PhpConverter\Dto\DtoType; | ||
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpBaseType; | ||
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpListType; | ||
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpOptionalType; | ||
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpTypeInterface; | ||
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpUnionType; | ||
use Riverwaysoft\PhpConverter\Dto\PhpType\PhpUnknownType; | ||
use Riverwaysoft\PhpConverter\OutputGenerator\UnknownTypeResolver\UnknownTypeResolverInterface; | ||
use Riverwaysoft\PhpConverter\OutputGenerator\UnsupportedTypeException; | ||
|
||
class GoTypeResolver | ||
{ | ||
/** @param UnknownTypeResolverInterface[] $unknownTypeResolvers */ | ||
public function __construct(private array $unknownTypeResolvers = []) {} | ||
|
||
public function getTypeFromPhp( | ||
PhpTypeInterface $type, | ||
?DtoType $dto, | ||
DtoList $dtoList | ||
): string { | ||
if ($type instanceof PhpUnionType) { | ||
$fn = fn(PhpTypeInterface $type) => $this->getTypeFromPhp( | ||
$type, | ||
$dto, | ||
$dtoList | ||
); | ||
$types = array_map($fn, $type->getTypes()); | ||
|
||
// Two args, one of them is null | ||
if (count($types) === 2 && in_array('null', $types)) { | ||
$types = array_diff($types, ['null']); | ||
|
||
return "*$types[0]"; | ||
} | ||
|
||
return 'any'; | ||
} | ||
|
||
if ($type instanceof PhpListType) { | ||
$listType = $this->getTypeFromPhp($type->getType(), $dto, $dtoList); | ||
|
||
if ($type->getType() instanceof PhpUnionType) { | ||
return sprintf('[](%s)', $listType); | ||
} | ||
|
||
return sprintf('[]%s', $listType); | ||
} | ||
|
||
if ($type instanceof PhpOptionalType) { | ||
return $this->getTypeFromPhp($type->getType(), $dto, $dtoList); | ||
} | ||
|
||
if ($type instanceof PhpBaseType) { | ||
return match (true) { | ||
$type->equalsTo(PhpBaseType::int()) => 'int', | ||
$type->equalsTo(PhpBaseType::float()) => 'float64', | ||
$type->equalsTo(PhpBaseType::string()) => 'string', | ||
$type->equalsTo(PhpBaseType::bool()) => 'bool', | ||
$type->equalsTo(PhpBaseType::mixed()), | ||
$type->equalsTo(PhpBaseType::object()) => 'any', | ||
$type->equalsTo(PhpBaseType::array()), | ||
$type->equalsTo(PhpBaseType::iterable()) => '[]any', | ||
$type->equalsTo(PhpBaseType::null()) => 'null', | ||
$type->equalsTo(PhpBaseType::self()) => $dto->getName(), | ||
default => throw new Exception( | ||
sprintf("Unknown base PHP type: %s", $type->jsonSerialize()) | ||
) | ||
}; | ||
} | ||
|
||
if ($type instanceof PhpUnknownType && $dto?->hasGeneric($type)) { | ||
return 'any'; | ||
} | ||
|
||
if ( | ||
$type instanceof PhpUnknownType && | ||
$type->hasGenerics() && ( | ||
$dtoList->hasDtoWithType($type->getName()) || | ||
!empty( | ||
$type->getContext()[PhpUnknownType::GENERIC_IGNORE_NO_RESOLVER] | ||
) | ||
) | ||
) { | ||
$result = $type->getName(); | ||
|
||
$generics = array_map( | ||
fn(PhpTypeInterface $innerGeneric) => $this->getTypeFromPhp( | ||
$innerGeneric, | ||
$dto, | ||
$dtoList, | ||
), | ||
$type->getGenerics() | ||
); | ||
|
||
$result .= sprintf("<%s>", join(', ', $generics)); | ||
|
||
return $result; | ||
} | ||
|
||
/** @var PhpUnknownType $type */ | ||
$result = $this->handleUnknownType($type, $dto, $dtoList); | ||
if ($result instanceof PhpTypeInterface) { | ||
return $this->getTypeFromPhp($result, $dto, $dtoList); | ||
} | ||
|
||
return $result; | ||
} | ||
|
||
private function handleUnknownType( | ||
PhpUnknownType $type, | ||
?DtoType $dto, | ||
DtoList $dtoList | ||
): string|PhpTypeInterface { | ||
foreach ($this->unknownTypeResolvers as $unknownTypeResolver) { | ||
if ($unknownTypeResolver->supports($type, $dto, $dtoList)) { | ||
return $unknownTypeResolver->resolve($type, $dto, $dtoList); | ||
} | ||
} | ||
|
||
throw UnsupportedTypeException::forType($type, $dto?->getName() ?? ''); | ||
} | ||
} |
Oops, something went wrong.