Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Modify composer.json - default
run: |
CURRENT_DIR=$(pwd)
for COMPONENT in $(find src/Service -maxdepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | sort)
for COMPONENT in $(find src/Service -maxdepth 2 -type f -name phpunit.xml.dist -printf '%h\n' | grep -v '.template' | sort)
do
echo ::group::$COMPONENT
echo "$CURRENT_DIR/$COMPONENT"
Expand All @@ -64,7 +64,7 @@ jobs:
done

cd "$CURRENT_DIR"
for COMPONENT in $(find src/Integration -maxdepth 3 -type f -name phpunit.xml.dist -printf '%h\n' | sort)
for COMPONENT in $(find src/Integration -maxdepth 3 -type f -name phpunit.xml.dist -printf '%h\n' | grep -v '.template' | sort)
do
echo ::group::$COMPONENT
echo "$CURRENT_DIR/$COMPONENT"
Expand All @@ -84,7 +84,7 @@ jobs:
SYMFONY_REQUIRE: '>=4.4'
run: |
CURRENT_DIR=$(pwd)
for COMPONENT in $(find src -maxdepth 4 -type f -name phpunit.xml.dist -printf '%h\n' | sort)
for COMPONENT in $(find src -maxdepth 4 -type f -name phpunit.xml.dist -printf '%h\n' | grep -v '.template' | sort)
do
echo ::group::$COMPONENT
echo "$CURRENT_DIR/$COMPONENT"
Expand All @@ -105,7 +105,7 @@ jobs:
run: |
ok=0
CURRENT_DIR=$(pwd)
for COMPONENT in $(find src -maxdepth 4 -type f -name phpunit.xml.dist -printf '%h\n' | sort)
for COMPONENT in $(find src -maxdepth 4 -type f -name phpunit.xml.dist -printf '%h\n' | grep -v '.template' | sort)
do
echo ::group::$COMPONENT
localExit=0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,12 @@ class PopulatorGenerator
*/
private $parserProvider;

public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $namespaceRegistry, RequirementsRegistry $requirementsRegistry, ObjectGenerator $objectGenerator, ?TypeGenerator $typeGenerator = null, ?EnumGenerator $enumGenerator = null, ?ParserProvider $parserProvider = null)
public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $namespaceRegistry, RequirementsRegistry $requirementsRegistry, ObjectGenerator $objectGenerator, array $managedMethods, ?TypeGenerator $typeGenerator = null, ?EnumGenerator $enumGenerator = null, ?ParserProvider $parserProvider = null)
{
$this->objectGenerator = $objectGenerator;
$this->requirementsRegistry = $requirementsRegistry;
$this->typeGenerator = $typeGenerator ?? new TypeGenerator($namespaceRegistry);
$this->enumGenerator = $enumGenerator ?? new EnumGenerator($classRegistry, $namespaceRegistry);
$this->enumGenerator = $enumGenerator ?? new EnumGenerator($classRegistry, $namespaceRegistry, $managedMethods);
$this->parserProvider = $parserProvider ?? new ParserProvider($namespaceRegistry, $requirementsRegistry, $this->typeGenerator);
}

Expand Down Expand Up @@ -277,7 +277,7 @@ private function generatePopulator(Operation $operation, StructureShape $shape,
foreach ($parserResult->getUsedClasses() as $className) {
$classBuilder->addUse($className->getFqdn());
}
$classBuilder->setMethods($parserResult->getExtraMethods());
$classBuilder->addMethods($parserResult->getExtraMethods());
}
if (empty(trim($body))) {
return;
Expand Down
68 changes: 67 additions & 1 deletion src/CodeGenerator/src/Generator/EnumGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@

namespace AsyncAws\CodeGenerator\Generator;

use AsyncAws\CodeGenerator\Definition\ListShape;
use AsyncAws\CodeGenerator\Definition\MapShape;
use AsyncAws\CodeGenerator\Definition\Shape;
use AsyncAws\CodeGenerator\Definition\StructureShape;
use AsyncAws\CodeGenerator\Generator\Naming\ClassName;
use AsyncAws\CodeGenerator\Generator\Naming\NamespaceRegistry;
use AsyncAws\CodeGenerator\Generator\PhpGenerator\ClassRegistry;
Expand All @@ -19,6 +22,8 @@
*/
class EnumGenerator
{
public const UNKNOWN_VALUE = 'UNKNOWN_TO_SDK';

/**
* @var ClassRegistry
*/
Expand All @@ -34,10 +39,21 @@ class EnumGenerator
*/
private $generated = [];

public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $namespaceRegistry)
/**
* @var list<string>
*/
private $managedMethods;

/**
* @var array<string, bool>|null
*/
private $usedShapedOutput;

public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $namespaceRegistry, array $managedMethods)
{
$this->classRegistry = $classRegistry;
$this->namespaceRegistry = $namespaceRegistry;
$this->managedMethods = $managedMethods;
}

/**
Expand All @@ -63,6 +79,11 @@ public function generate(Shape $shape): ClassName
}
ksort($consts);
$availableConsts = [];

if ($this->isShapeUsedOutput($shape)) {
$classBuilder->addConstant(self::UNKNOWN_VALUE, self::UNKNOWN_VALUE)->setVisibility(Visibility::Public);
}

foreach ($consts as $constName => $constValue) {
$classBuilder->addConstant($constName, $constValue)->setVisibility(Visibility::Public);
$availableConsts[] = 'self::' . $constName . ' => true';
Expand Down Expand Up @@ -103,4 +124,49 @@ public static function canonicalizeName(string $name): string

return $name;
}

private function isShapeUsedOutput(Shape $shape): bool
{
if (null === $this->usedShapedOutput) {
$service = $shape->getService();
$walk = function (?Shape $shape) use (&$walk) {
if (null === $shape) {
return;
}
if (isset($this->usedShapedOutput[$shape->getName()])) {
// Node already visited
return;
}

$this->usedShapedOutput[$shape->getName()] = true;
if ($shape instanceof StructureShape) {
foreach ($shape->getMembers() as $member) {
$walk($member->getShape());
}
} elseif ($shape instanceof ListShape) {
$walk($shape->getMember()->getShape());
} elseif ($shape instanceof MapShape) {
$walk($shape->getKey()->getShape());
$walk($shape->getValue()->getShape());
}
};

foreach ($this->managedMethods as $method) {
if (null !== $operation = $service->getOperation($method)) {
$walk($operation->getOutput());
foreach ($operation->getErrors() as $error) {
$walk($error);
}
}
if (null !== $waiter = $service->getWaiter($method)) {
$walk($waiter->getOperation()->getOutput());
foreach ($waiter->getOperation()->getErrors() as $error) {
$walk($error);
}
}
}
}

return $this->usedShapedOutput[$shape->getName()] ?? false;
}
}
4 changes: 2 additions & 2 deletions src/CodeGenerator/src/Generator/InputGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ class InputGenerator
*/
private $requirementsRegistry;

public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $namespaceRegistry, RequirementsRegistry $requirementsRegistry, ObjectGenerator $objectGenerator, ?TypeGenerator $typeGenerator = null, ?EnumGenerator $enumGenerator = null, ?HookGenerator $hookGenerator = null)
public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $namespaceRegistry, RequirementsRegistry $requirementsRegistry, ObjectGenerator $objectGenerator, array $managedMethods, ?TypeGenerator $typeGenerator = null, ?EnumGenerator $enumGenerator = null, ?HookGenerator $hookGenerator = null)
{
$this->classRegistry = $classRegistry;
$this->namespaceRegistry = $namespaceRegistry;
$this->objectGenerator = $objectGenerator;
$this->typeGenerator = $typeGenerator ?? new TypeGenerator($this->namespaceRegistry);
$this->enumGenerator = $enumGenerator ?? new EnumGenerator($this->classRegistry, $this->namespaceRegistry);
$this->enumGenerator = $enumGenerator ?? new EnumGenerator($this->classRegistry, $this->namespaceRegistry, $managedMethods);
$this->hookGenerator = $hookGenerator ?? new HookGenerator();
$this->serializer = new SerializerProvider($this->namespaceRegistry, $requirementsRegistry);
$this->requirementsRegistry = $requirementsRegistry;
Expand Down
3 changes: 2 additions & 1 deletion src/CodeGenerator/src/Generator/ObjectGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public function __construct(ClassRegistry $classRegistry, NamespaceRegistry $nam
$this->classRegistry = $classRegistry;
$this->namespaceRegistry = $namespaceRegistry;
$this->typeGenerator = $typeGenerator ?? new TypeGenerator($this->namespaceRegistry);
$this->enumGenerator = $enumGenerator ?? new EnumGenerator($this->classRegistry, $this->namespaceRegistry);
$this->enumGenerator = $enumGenerator ?? new EnumGenerator($this->classRegistry, $this->namespaceRegistry, $managedMethods);
$this->serializer = new SerializerProvider($this->namespaceRegistry, $requirementsRegistry);
$this->managedMethods = $managedMethods;
}
Expand Down Expand Up @@ -139,6 +139,7 @@ private function isShapeUsedInput(StructureShape $shape): bool
} elseif ($shape instanceof ListShape) {
$walk($shape->getMember()->getShape());
} elseif ($shape instanceof MapShape) {
$walk($shape->getKey()->getShape());
$walk($shape->getValue()->getShape());
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ public function hasMethod(string $name): bool
/**
* @param Method[] $methods
*/
public function setMethods(array $methods): self
public function addMethods(array $methods): self
{
$methods = array_merge($methods, $this->class->getMethods());
$this->class->setMethods($methods);

return $this;
Expand Down
2 changes: 1 addition & 1 deletion src/CodeGenerator/src/Generator/ResponseParser/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@ interface Parser
{
public function generate(StructureShape $shape, bool $throwOnError = true): ParserResult;

public function generateForPath(StructureShape $shape, string $path, string $output): string;
public function generateForPath(StructureShape $shape, string $path, string $output): ParserResult;
}
60 changes: 53 additions & 7 deletions src/CodeGenerator/src/Generator/ResponseParser/RestJsonParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use AsyncAws\CodeGenerator\Definition\StructureShape;
use AsyncAws\CodeGenerator\Generator\CodeGenerator\TypeGenerator;
use AsyncAws\CodeGenerator\Generator\Composer\RequirementsRegistry;
use AsyncAws\CodeGenerator\Generator\EnumGenerator;
use AsyncAws\CodeGenerator\Generator\GeneratorHelper;
use AsyncAws\CodeGenerator\Generator\Naming\ClassName;
use AsyncAws\CodeGenerator\Generator\Naming\NamespaceRegistry;
Expand Down Expand Up @@ -113,8 +114,11 @@ public function generate(StructureShape $shape, bool $throwOnError = true): Pars
return new ParserResult($body, $this->imports, $this->functions);
}

public function generateForPath(StructureShape $shape, string $path, string $output): string
public function generateForPath(StructureShape $shape, string $path, string $output): ParserResult
{
$this->functions = [];
$this->imports = [];

if (null !== $wrapper = $shape->getResultWrapper()) {
$body = '$data = $response->toArray();' . "\n";
$body .= strtr('$data = $data[WRAPPER];' . "\n", ['WRAPPER' => var_export($wrapper, true)]);
Expand All @@ -132,11 +136,13 @@ public function generateForPath(StructureShape $shape, string $path, string $out
$accesor .= '[' . var_export($this->getInputAccessorName($member), true) . ']';
}

return $body . strtr('OUTPUT = INPUTPATH ?? null', [
$body .= strtr('OUTPUT = INPUTPATH ?? null', [
'INPUT' => $input,
'PATH' => $accesor,
'OUTPUT' => $output,
]);

return new ParserResult($body, $this->imports, $this->functions);
}

protected function parseResponseTimestamp(Shape $shape, string $input, bool $required): string
Expand Down Expand Up @@ -200,6 +206,10 @@ private function parseElement(string $input, Shape $shape, bool $required, bool

switch ($shape->getType()) {
case 'string':
if (!empty($shape->getEnum())) {
return $this->parseResponseEnum($shape, $input, $required);
}

return $this->parseResponseString($input, $required);
case 'long':
case 'integer':
Expand Down Expand Up @@ -262,6 +272,25 @@ private function parseResponseString(string $input, bool $required): string
return strtr('isset(INPUT) ? (string) INPUT : null', ['INPUT' => $input]);
}

private function parseResponseEnum(Shape $shape, string $input, bool $required): string
{
$className = $this->namespaceRegistry->getEnum($shape);
$this->imports[] = $className;
if ($required) {
return strtr('!ENUM_CLASS::exists((string) INPUT) ? ENUM_CLASS::UNKNOWN_VALUE_CONST : (string) INPUT', [
'ENUM_CLASS' => $className->getName(),
'UNKNOWN_VALUE_CONST' => EnumGenerator::UNKNOWN_VALUE,
'INPUT' => $input,
]);
}

return strtr('isset(INPUT) ? (!ENUM_CLASS::exists((string) INPUT) ? ENUM_CLASS::UNKNOWN_VALUE_CONST : (string) INPUT) : null', [
'ENUM_CLASS' => $className->getName(),
'UNKNOWN_VALUE_CONST' => EnumGenerator::UNKNOWN_VALUE,
'INPUT' => $input,
]);
}

private function parseResponseInteger(string $input, bool $required): string
{
if ($required) {
Expand Down Expand Up @@ -361,42 +390,59 @@ private function parseResponseMap(MapShape $shape, string $input, bool $required
// prevent recursion
$this->generatedFunctions[$functionName] = true;

if (!empty($shape->getKey()->getShape()->getEnum())) {
$className = $this->namespaceRegistry->getEnum($shape->getKey()->getShape());
$this->imports[] = $className;
$keyCode = strtr('!ENUM_CLASS::exists(KEY) ? ENUM_CLASS::UNKNOWN_VALUE_CONST : KEY', [
'ENUM_CLASS' => $className->getName(),
'UNKNOWN_VALUE_CONST' => EnumGenerator::UNKNOWN_VALUE,
]);
} else {
$keyCode = 'KEY';
}

if (null === $locationName = $shape->getKey()->getLocationName()) {
$keyCode = strtr($keyCode, ['KEY' => '(string) $name']);
// We need to use array keys
if ($shapeValue->getShape() instanceof StructureShape) {
$body = '
$items = [];
foreach ($json as $name => $value) {
$items[(string) $name] = BUILDER_CODE;
$items[KEY] = BUILDER_CODE;
}

return $items;
';

$this->functions[$functionName] = $this->createPopulateMethod($functionName, strtr($body, [
'BUILDER_CODE' => $this->parseResponseStructure($shapeValue->getShape(), '$value', true),
'KEY' => $keyCode,
]), $shape);
} else {
$body = '
$items = [];
foreach ($json as $name => $value) {
$items[(string) $name] = CODE;
$items[KEY] = CODE;
}

return $items;
';

$this->functions[$functionName] = $this->createPopulateMethod($functionName, strtr($body, [
'CODE' => $this->parseElement('$value', $shapeValue->getShape(), true, $inObject),
'KEY' => $keyCode,
]), $shape);
}
} else {
$keyCode = strtr($keyCode, [
'KEY' => strtr('$item[MAP_KEY]', ['MAP_KEY' => var_export($locationName, true)]),
]);
$inputAccessorName = $this->getInputAccessorName($shapeValue);
if ($shapeValue->getShape() instanceof StructureShape) {
$body = '
$items = [];
foreach ($json as $item) {
$items[$item[MAP_KEY]] = MAP_ACCESSOR;
$items[KEY] = MAP_ACCESSOR;
}

return $items;
Expand All @@ -407,7 +453,7 @@ private function parseResponseMap(MapShape $shape, string $input, bool $required
foreach ($json as $item) {
$a = MAP_ACCESSOR;
if (null !== $a) {
$items[$item[MAP_KEY]] = $a;
$items[KEY] = $a;
}
}

Expand All @@ -416,8 +462,8 @@ private function parseResponseMap(MapShape $shape, string $input, bool $required
}

$this->functions[$functionName] = $this->createPopulateMethod($functionName, strtr($body, [
'MAP_KEY' => var_export($locationName, true),
'MAP_ACCESSOR' => $this->parseElement(\sprintf('$item[\'%s\']', $inputAccessorName), $shapeValue->getShape(), false, $inObject),
'KEY' => $keyCode,
]), $shape);
}
}
Expand Down
Loading